diff --git a/lib/src/validator/dependency.dart b/lib/src/validator/dependency.dart
index 1715240ca08c11e7573594b15558168ecfe03f61..aa216713e96412066dee31028fe6787111ec4a6f 100644
--- a/lib/src/validator/dependency.dart
+++ b/lib/src/validator/dependency.dart
@@ -7,6 +7,7 @@ library pub.validator.dependency;
 import 'dart:async';
 
 import '../entrypoint.dart';
+import '../log.dart' as log;
 import '../package.dart';
 import '../validator.dart';
 import '../version.dart';
@@ -22,7 +23,17 @@ class DependencyValidator extends Validator {
         return _warnAboutSource(dependency);
       }
 
-      if (dependency.constraint.isAny) _warnAboutConstraint(dependency);
+      if (dependency.constraint.isAny) {
+        _warnAboutNoConstraint(dependency);
+      } else if (dependency.constraint is Version) {
+        _warnAboutSingleVersionConstraint(dependency);
+      } else if (dependency.constraint is VersionRange) {
+        if (dependency.constraint.min == null) {
+          _warnAboutNoConstraintLowerBound(dependency);
+        } else if (dependency.constraint.max == null) {
+          _warnAboutNoConstraintUpperBound(dependency);
+        }
+      }
 
       return new Future.value();
     });
@@ -63,7 +74,7 @@ class DependencyValidator extends Validator {
   }
 
   /// Warn that dependencies should have version constraints.
-  void _warnAboutConstraint(PackageDep dep) {
+  void _warnAboutNoConstraint(PackageDep dep) {
     var lockFile = entrypoint.loadLockFile();
     var message = 'Your dependency on "${dep.name}" should have a version '
         'constraint.';
@@ -75,15 +86,69 @@ class DependencyValidator extends Validator {
         '  ${dep.name}: ${_constraintForVersion(locked.version)}\n';
     }
     warnings.add("$message\n"
-        "Without a constraint, you're promising to support all future "
-        "versions of ${dep.name}.");
+        'Without a constraint, you\'re promising to support ${log.bold("all")} '
+            'future versions of "${dep.name}".');
+  }
+
+  // Warn that dependencies should allow more than a single version.
+  void _warnAboutSingleVersionConstraint(PackageDep dep) {
+    warnings.add(
+        'Your dependency on "${dep.name}" should allow more than one version. '
+            'For example:\n'
+        '\n'
+        'dependencies:\n'
+        '  ${dep.name}: ${_constraintForVersion(dep.constraint)}\n'
+        '\n'
+        'Constraints that are too tight will make it difficult for people to '
+            'use your package\n'
+        'along with other packages that also depend on "${dep.name}".');
+  }
+
+  // Warn that dependencies should have lower bounds on their constraints.
+  void _warnAboutNoConstraintLowerBound(PackageDep dep) {
+    var message = 'Your dependency on "${dep.name}" should have a lower bound.';
+    var locked = entrypoint.loadLockFile().packages[dep.name];
+    if (locked != null) {
+      var constraint;
+      if (locked.version == dep.constraint.max) {
+        constraint = _constraintForVersion(locked.version);
+      } else {
+        constraint = '">=${locked.version} ${dep.constraint}"';
+      }
+
+      message = '$message For example:\n'
+        '\n'
+        'dependencies:\n'
+        '  ${dep.name}: $constraint\n';
+    }
+    warnings.add("$message\n"
+        'Without a constraint, you\'re promising to support ${log.bold("all")} '
+            'previous versions of "${dep.name}".');
+  }
+
+  // Warn that dependencies should have upper bounds on their constraints.
+  void _warnAboutNoConstraintUpperBound(PackageDep dep) {
+    warnings.add(
+        'Your dependency on "${dep.name}" should have an upper bound. For '
+            'example:\n'
+        '\n'
+        'dependencies:\n'
+        '  ${dep.name}: "${dep.constraint} '
+            '${_upperBoundForVersion(dep.constraint.min)}"\n'
+        '\n'
+        'Without an upper bound, you\'re promising to support '
+            '${log.bold("all")} future versions of ${dep.name}.');
   }
 
   /// Returns the suggested version constraint for a dependency that was tested
   /// against [version].
-  String _constraintForVersion(Version version) {
-    if (version.major != 0) return '">=$version <${version.major + 1}.0.0"';
-    return '">=$version <${version.major}.${version.minor}.'
-        '${version.patch + 1}"';
+  String _constraintForVersion(Version version) =>
+      '">=$version ${_upperBoundForVersion(version)}"';
+
+  /// Returns the suggested upper bound for a dependency that was tested against
+  /// [version].
+  String _upperBoundForVersion(Version version) {
+    if (version.major != 0) return '<${version.major + 1}.0.0';
+    return '<${version.major}.${version.minor + 1}.0';
   }
 }
diff --git a/lib/src/version.dart b/lib/src/version.dart
index 1e92a3bda10a807e9ab615d13a66865e273b1f02..7577f9fe62524fc8c343e34b17a7aa840e0565dd 100644
--- a/lib/src/version.dart
+++ b/lib/src/version.dart
@@ -449,7 +449,7 @@ class VersionRange implements VersionConstraint {
 
   bool get isEmpty => false;
 
-  bool get isAny => !includeMin && !includeMax;
+  bool get isAny => min == null && max == null;
 
   /// Tests if [other] matches falls within this version range.
   bool allows(Version other) {
diff --git a/test/validator/dependency_test.dart b/test/validator/dependency_test.dart
index 53dfff98294307f7ef7b857bd48341266a2fcb9e..8c53c744c9ef64482df360a1ac31579661b12f85 100644
--- a/test/validator/dependency_test.dart
+++ b/test/validator/dependency_test.dart
@@ -84,7 +84,7 @@ main() {
                     "pre-1.0.0", () {
           setUpDependency({'git': 'git://github.com/dart-lang/foo'},
               hostedVersions: ["0.0.1", "0.0.2"]);
-          expectDependencyValidationWarning('  foo: ">=0.0.2 <0.0.3"');
+          expectDependencyValidationWarning('  foo: ">=0.0.2 <0.1.0"');
         });
       });
 
@@ -127,7 +127,7 @@ main() {
                     "pre-1.0.0", () {
           setUpDependency({'path': path.join(sandboxDir, 'foo')},
               hostedVersions: ["0.0.1", "0.0.2"]);
-          expectDependencyValidationError('  foo: ">=0.0.2 <0.0.3"');
+          expectDependencyValidationError('  foo: ">=0.0.2 <0.1.0"');
         });
       });
 
@@ -233,9 +233,152 @@ main() {
             }))
           ]).create();
 
-          expectDependencyValidationWarning('  foo: ">=0.1.2 <0.1.3"');
+          expectDependencyValidationWarning('  foo: ">=0.1.2 <0.2.0"');
         });
       });
     });
+
+    integration('with a single-version dependency and it should suggest a '
+        'constraint based on the version', () {
+      d.dir(appPath, [
+        d.libPubspec("test_pkg", "1.0.0", deps: {
+          "foo": "1.2.3"
+        })
+      ]).create();
+
+      expectDependencyValidationWarning('  foo: ">=1.2.3 <2.0.0"');
+    });
+
+    group('has a dependency without a lower bound', () {
+      group('and it should not suggest a version', () {
+        integration("if there's no lockfile", () {
+          d.dir(appPath, [
+            d.libPubspec("test_pkg", "1.0.0", deps: {
+              "foo": "<3.0.0"
+            })
+          ]).create();
+
+          expect(schedulePackageValidation(dependency), completion(
+              pairOf(isEmpty, everyElement(isNot(contains("\n  foo:"))))));
+        });
+
+        integration("if the lockfile doesn't have an entry for the "
+            "dependency", () {
+          d.dir(appPath, [
+            d.libPubspec("test_pkg", "1.0.0", deps: {
+              "foo": "<3.0.0"
+            }),
+            d.file("pubspec.lock", JSON.encode({
+              'packages': {
+                'bar': {
+                  'version': '1.2.3',
+                  'source': 'hosted',
+                  'description': {
+                    'name': 'bar',
+                    'url': 'http://pub.dartlang.org'
+                  }
+                }
+              }
+            }))
+          ]).create();
+
+          expect(schedulePackageValidation(dependency), completion(
+              pairOf(isEmpty, everyElement(isNot(contains("\n  foo:"))))));
+        });
+      });
+
+      group('with a lockfile', () {
+        integration('and it should suggest a constraint based on the locked '
+            'version', () {
+          d.dir(appPath, [
+            d.libPubspec("test_pkg", "1.0.0", deps: {
+              "foo": "<3.0.0"
+            }),
+            d.file("pubspec.lock", JSON.encode({
+              'packages': {
+                'foo': {
+                  'version': '1.2.3',
+                  'source': 'hosted',
+                  'description': {
+                    'name': 'foo',
+                    'url': 'http://pub.dartlang.org'
+                  }
+                }
+              }
+            }))
+          ]).create();
+
+          expectDependencyValidationWarning('  foo: ">=1.2.3 <3.0.0"');
+        });
+
+        integration('and it should preserve the upper-bound operator', () {
+          d.dir(appPath, [
+            d.libPubspec("test_pkg", "1.0.0", deps: {
+              "foo": "<=3.0.0"
+            }),
+            d.file("pubspec.lock", JSON.encode({
+              'packages': {
+                'foo': {
+                  'version': '1.2.3',
+                  'source': 'hosted',
+                  'description': {
+                    'name': 'foo',
+                    'url': 'http://pub.dartlang.org'
+                  }
+                }
+              }
+            }))
+          ]).create();
+
+          expectDependencyValidationWarning('  foo: ">=1.2.3 <=3.0.0"');
+        });
+
+        integration('and it should expand the suggested constraint if the '
+            'locked version matches the upper bound', () {
+          d.dir(appPath, [
+            d.libPubspec("test_pkg", "1.0.0", deps: {
+              "foo": "<=1.2.3"
+            }),
+            d.file("pubspec.lock", JSON.encode({
+              'packages': {
+                'foo': {
+                  'version': '1.2.3',
+                  'source': 'hosted',
+                  'description': {
+                    'name': 'foo',
+                    'url': 'http://pub.dartlang.org'
+                  }
+                }
+              }
+            }))
+          ]).create();
+
+          expectDependencyValidationWarning('  foo: ">=1.2.3 <2.0.0"');
+        });
+      });
+    });
+
+    group('with a dependency without an upper bound', () {
+      integration('and it should suggest a constraint based on the lower bound',
+          () {
+        d.dir(appPath, [
+          d.libPubspec("test_pkg", "1.0.0", deps: {
+            "foo": ">=1.2.3"
+          })
+        ]).create();
+
+        expectDependencyValidationWarning('  foo: ">=1.2.3 <2.0.0"');
+      });
+
+      integration('and it should preserve the lower-bound operator', () {
+        d.dir(appPath, [
+          d.libPubspec("test_pkg", "1.0.0", deps: {
+            "foo": ">1.2.3"
+          })
+        ]).create();
+
+        expectDependencyValidationWarning('  foo: ">1.2.3 <2.0.0"');
+      });
+    });
   });
 }
diff --git a/test/version_test.dart b/test/version_test.dart
index 0e7452a6524e2cf5db919df1b986e9084d3e4ff5..8e6a8254e4d115b485824b028d4f322c8d40dc71 100644
--- a/test/version_test.dart
+++ b/test/version_test.dart
@@ -207,18 +207,21 @@ main() {
     group('constructor', () {
       test('takes a min and max', () {
         var range = new VersionRange(min: v123, max: v124);
+        expect(range.isAny, isFalse);
         expect(range.min, equals(v123));
         expect(range.max, equals(v124));
       });
 
       test('allows omitting max', () {
         var range = new VersionRange(min: v123);
+        expect(range.isAny, isFalse);
         expect(range.min, equals(v123));
         expect(range.max, isNull);
       });
 
       test('allows omitting min and max', () {
         var range = new VersionRange();
+        expect(range.isAny, isTrue);
         expect(range.min, isNull);
         expect(range.max, isNull);
       });
@@ -367,6 +370,7 @@ main() {
 
     test('empty', () {
       expect(VersionConstraint.empty.isEmpty, isTrue);
+      expect(VersionConstraint.empty.isAny, isFalse);
       expect(VersionConstraint.empty, doesNotAllow([
         new Version.parse('0.0.0-blah'),
         new Version.parse('1.2.3'),