diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index 92880e9cbf8aecff8cfb82f75a78ed04a1b00597..a10edcc6fcea9b85a196eed554e3f98ced90e90c 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -1207,6 +1207,13 @@ def common_dependencies(self, other):
         return common
 
 
+    def constrained(self, other, deps=True):
+        """Return a constrained copy without modifying this spec."""
+        clone = self.copy(deps=deps)
+        clone.constrain(other, deps)
+        return clone
+
+
     def dep_difference(self, other):
         """Returns dependencies in self that are not in other."""
         mine = set(s.name for s in self.traverse(root=False))
diff --git a/lib/spack/spack/test/spec_semantics.py b/lib/spack/spack/test/spec_semantics.py
index 6666dbbb52c794c21e530a2762c365ec5281708f..64220e589339aa6031d175ca13bd14dcbd862032 100644
--- a/lib/spack/spack/test/spec_semantics.py
+++ b/lib/spack/spack/test/spec_semantics.py
@@ -190,11 +190,23 @@ def test_unsatisfiable_variant_mismatch(self):
 
 
     def test_satisfies_virtual(self):
+        # Don't use check_satisfies: it checks constrain() too, and
+        # you can't constrain a non-virtual by a virtual.
         self.assertTrue(Spec('mpich').satisfies(Spec('mpi')))
         self.assertTrue(Spec('mpich2').satisfies(Spec('mpi')))
         self.assertTrue(Spec('zmpi').satisfies(Spec('mpi')))
 
 
+    def test_satisfies_virtual_dep_with_virtual_constraint(self):
+        """Ensure we can satisfy virtual constraints when there are multiple
+           vdep providers in the specs."""
+        self.assertTrue(Spec('netlib-lapack ^openblas').satisfies('netlib-lapack ^openblas'))
+        self.assertFalse(Spec('netlib-lapack ^netlib-blas').satisfies('netlib-lapack ^openblas'))
+
+        self.assertFalse(Spec('netlib-lapack ^openblas').satisfies('netlib-lapack ^netlib-blas'))
+        self.assertTrue(Spec('netlib-lapack ^netlib-blas').satisfies('netlib-lapack ^netlib-blas'))
+
+
     # ================================================================================
     # Indexing specs
     # ================================================================================
@@ -327,4 +339,3 @@ def test_constrain_dependency_not_changed(self):
         self.check_constrain_not_changed('libelf^foo+debug', 'libelf^foo+debug')
         self.check_constrain_not_changed('libelf^foo~debug', 'libelf^foo~debug')
         self.check_constrain_not_changed('libelf^foo=bgqos_0', 'libelf^foo=bgqos_0')
-
diff --git a/lib/spack/spack/virtual.py b/lib/spack/spack/virtual.py
index c77b259d6115e15a9629a90fa6bfdb0659104b79..f92cc4509c53da559407ec2dc0d0664f2ce3979a 100644
--- a/lib/spack/spack/virtual.py
+++ b/lib/spack/spack/virtual.py
@@ -117,12 +117,13 @@ def providers_for(self, *vpkg_specs):
         return sorted(providers)
 
 
-    # TODO: this is pretty darned nasty, and inefficient.
+    # TODO: this is pretty darned nasty, and inefficient, but there
+    # are not that many vdeps in most specs.
     def _cross_provider_maps(self, lmap, rmap):
         result = {}
         for lspec, rspec in itertools.product(lmap, rmap):
             try:
-                constrained = lspec.copy().constrain(rspec)
+                constrained = lspec.constrained(rspec)
             except spack.spec.UnsatisfiableSpecError:
                 continue
 
@@ -130,7 +131,7 @@ def _cross_provider_maps(self, lmap, rmap):
             for lp_spec, rp_spec in itertools.product(lmap[lspec], rmap[rspec]):
                 if lp_spec.name == rp_spec.name:
                     try:
-                        const = lp_spec.copy().constrain(rp_spec,deps=False)
+                        const = lp_spec.constrained(rp_spec, deps=False)
                         result.setdefault(constrained, set()).add(const)
                     except spack.spec.UnsatisfiableSpecError:
                         continue
@@ -157,4 +158,4 @@ def satisfies(self, other):
             if crossed:
                 result[name] = crossed
 
-        return bool(result)
+        return all(c in result for c in common)
diff --git a/var/spack/mock_packages/netlib-blas/package.py b/var/spack/mock_packages/netlib-blas/package.py
new file mode 100644
index 0000000000000000000000000000000000000000..199327812e1b6ce89712bdd1910ef0d3b4a6d707
--- /dev/null
+++ b/var/spack/mock_packages/netlib-blas/package.py
@@ -0,0 +1,36 @@
+##############################################################################
+# Copyright (c) 2013-2015, Lawrence Livermore National Security, LLC.
+# Produced at the Lawrence Livermore National Laboratory.
+#
+# This file is part of Spack.
+# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
+# LLNL-CODE-647188
+#
+# For details, see https://scalability-llnl.github.io/spack
+# Please also see the LICENSE file for our notice and the LGPL.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License (as published by
+# the Free Software Foundation) version 2.1 dated February 1999.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
+# conditions of the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+from spack import *
+
+class NetlibBlas(Package):
+    homepage = "http://www.netlib.org/lapack/"
+    url      = "http://www.netlib.org/lapack/lapack-3.5.0.tgz"
+
+    version('3.5.0', 'b1d3e3e425b2e44a06760ff173104bdf')
+
+    provides('blas')
+
+    def install(self, spec, prefix):
+        pass
diff --git a/var/spack/mock_packages/netlib-lapack/package.py b/var/spack/mock_packages/netlib-lapack/package.py
new file mode 100644
index 0000000000000000000000000000000000000000..8f7f236f1b4ef45e43cc94611771ee9dfb4f276e
--- /dev/null
+++ b/var/spack/mock_packages/netlib-lapack/package.py
@@ -0,0 +1,37 @@
+##############################################################################
+# Copyright (c) 2013-2015, Lawrence Livermore National Security, LLC.
+# Produced at the Lawrence Livermore National Laboratory.
+#
+# This file is part of Spack.
+# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
+# LLNL-CODE-647188
+#
+# For details, see https://scalability-llnl.github.io/spack
+# Please also see the LICENSE file for our notice and the LGPL.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License (as published by
+# the Free Software Foundation) version 2.1 dated February 1999.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
+# conditions of the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+from spack import *
+
+class NetlibLapack(Package):
+    homepage = "http://www.netlib.org/lapack/"
+    url      = "http://www.netlib.org/lapack/lapack-3.5.0.tgz"
+
+    version('3.5.0', 'b1d3e3e425b2e44a06760ff173104bdf')
+
+    provides('lapack')
+    depends_on('blas')
+
+    def install(self, spec, prefix):
+        pass
diff --git a/var/spack/mock_packages/openblas/package.py b/var/spack/mock_packages/openblas/package.py
new file mode 100644
index 0000000000000000000000000000000000000000..9c2fb30573556f47c1a8b6c8adfee5a0dd5a6b7c
--- /dev/null
+++ b/var/spack/mock_packages/openblas/package.py
@@ -0,0 +1,37 @@
+##############################################################################
+# Copyright (c) 2013-2015, Lawrence Livermore National Security, LLC.
+# Produced at the Lawrence Livermore National Laboratory.
+#
+# This file is part of Spack.
+# Written by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
+# LLNL-CODE-647188
+#
+# For details, see https://scalability-llnl.github.io/spack
+# Please also see the LICENSE file for our notice and the LGPL.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License (as published by
+# the Free Software Foundation) version 2.1 dated February 1999.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the terms and
+# conditions of the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##############################################################################
+from spack import *
+
+class Openblas(Package):
+    """OpenBLAS: An optimized BLAS library"""
+    homepage = "http://www.openblas.net"
+    url      = "http://github.com/xianyi/OpenBLAS/archive/v0.2.15.tar.gz"
+
+    version('0.2.15', 'b1190f3d3471685f17cfd1ec1d252ac9')
+
+    provides('blas')
+
+    def install(self, spec, prefix):
+        pass