diff --git a/CHANGELOG.md b/CHANGELOG.md
index b4f91042ed..2d60164f97 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,7 +10,15 @@
 
 #### Enhancements
 
-* None.
+* Add `deployment_target` rule to validate that `@availability` attributes and
+  `#available` conditions are not using a version that is satisfied by the
+  deployment target. Since SwiftLint can't read an Xcode project, you need to
+  configure this rule with these keys: `iOS_deployment_target`,
+  `macOS_deployment_target`, `watchOS_deployment_target` and
+  `tvOS_deployment_target`. By default, these values are configured with the
+  minimum versions supported by Swift.  
+  [Marcelo Fabri](https://github.com/marcelofabri)
+  [#2589](https://github.com/realm/SwiftLint/issues/2589)
 
 #### Bug Fixes
 
diff --git a/Rules.md b/Rules.md
index 812bc1b4b4..f5c61f7652 100644
--- a/Rules.md
+++ b/Rules.md
@@ -21,6 +21,7 @@
 * [Convenience Type](#convenience-type)
 * [Custom Rules](#custom-rules)
 * [Cyclomatic Complexity](#cyclomatic-complexity)
+* [Deployment Target](#deployment-target)
 * [Discarded Notification Center Observer](#discarded-notification-center-observer)
 * [Discouraged Direct Initialization](#discouraged-direct-initialization)
 * [Discouraged Object Literal](#discouraged-object-literal)
@@ -2900,6 +2901,115 @@ if true {}; if true {}; if true {}; if true {}; if true {}
 
 
 
+## Deployment Target
+
+Identifier | Enabled by default | Supports autocorrection | Kind | Analyzer | Minimum Swift Compiler Version
+--- | --- | --- | --- | --- | ---
+`deployment_target` | Enabled | No | lint | No | 4.1.0 
+
+Availability checks or attributes shouldn't be using older versions that are satisfied by the deployment target.
+
+### Examples
+
+<details>
+<summary>Non Triggering Examples</summary>
+
+```swift
+@available(iOS 12.0, *)
+class A {}
+```
+
+```swift
+@available(watchOS 4.0, *)
+class A {}
+```
+
+```swift
+@available(swift 3.0.2)
+class A {}
+```
+
+```swift
+class A {}
+```
+
+```swift
+if #available(iOS 10.0, *) {}
+```
+
+```swift
+if #available(iOS 10, *) {}
+```
+
+```swift
+guard #available(iOS 12.0, *) else { return }
+```
+
+</details>
+<details>
+<summary>Triggering Examples</summary>
+
+```swift
+↓@available(iOS 6.0, *)
+class A {}
+```
+
+```swift
+↓@available(iOS 7.0, *)
+class A {}
+```
+
+```swift
+↓@available(iOS 6, *)
+class A {}
+```
+
+```swift
+↓@available(iOS 6.0, macOS 10.12, *)
+ class A {}
+```
+
+```swift
+↓@available(macOS 10.12, iOS 6.0, *)
+ class A {}
+```
+
+```swift
+↓@available(macOS 10.7, *)
+class A {}
+```
+
+```swift
+↓@available(OSX 10.7, *)
+class A {}
+```
+
+```swift
+↓@available(watchOS 0.9, *)
+class A {}
+```
+
+```swift
+↓@available(tvOS 8, *)
+class A {}
+```
+
+```swift
+if ↓#available(iOS 6.0, *) {}
+```
+
+```swift
+if ↓#available(iOS 6, *) {}
+```
+
+```swift
+guard ↓#available(iOS 6.0, *) else { return }
+```
+
+</details>
+
+
+
 ## Discarded Notification Center Observer
 
 Identifier | Enabled by default | Supports autocorrection | Kind | Analyzer | Minimum Swift Compiler Version
diff --git a/Source/SwiftLintFramework/Models/MasterRuleList.swift b/Source/SwiftLintFramework/Models/MasterRuleList.swift
index ac01d9112b..ebc9d5ca5d 100644
--- a/Source/SwiftLintFramework/Models/MasterRuleList.swift
+++ b/Source/SwiftLintFramework/Models/MasterRuleList.swift
@@ -22,6 +22,7 @@ public let masterRuleList = RuleList(rules: [
     ConvenienceTypeRule.self,
     CustomRules.self,
     CyclomaticComplexityRule.self,
+    DeploymentTargetRule.self,
     DiscardedNotificationCenterObserverRule.self,
     DiscouragedDirectInitRule.self,
     DiscouragedObjectLiteralRule.self,
diff --git a/Source/SwiftLintFramework/Rules/Lint/DeploymentTargetRule.swift b/Source/SwiftLintFramework/Rules/Lint/DeploymentTargetRule.swift
new file mode 100644
index 0000000000..c6102123d0
--- /dev/null
+++ b/Source/SwiftLintFramework/Rules/Lint/DeploymentTargetRule.swift
@@ -0,0 +1,141 @@
+import Foundation
+import SourceKittenFramework
+
+public struct DeploymentTargetRule: ConfigurationProviderRule {
+    private typealias Version = DeploymentTargetConfiguration.Version
+    public var configuration = DeploymentTargetConfiguration()
+
+    public init() {}
+
+    public static let description = RuleDescription(
+        identifier: "deployment_target",
+        name: "Deployment Target",
+        description: "Availability checks or attributes shouldn't be using older versions " +
+                     "that are satisfied by the deployment target.",
+        kind: .lint,
+        minSwiftVersion: .fourDotOne,
+        nonTriggeringExamples: [
+            "@available(iOS 12.0, *)\nclass A {}",
+            "@available(watchOS 4.0, *)\nclass A {}",
+            "@available(swift 3.0.2)\nclass A {}",
+            "class A {}",
+            "if #available(iOS 10.0, *) {}",
+            "if #available(iOS 10, *) {}",
+            "guard #available(iOS 12.0, *) else { return }"
+        ],
+        triggeringExamples: [
+            "↓@available(iOS 6.0, *)\nclass A {}",
+            "↓@available(iOS 7.0, *)\nclass A {}",
+            "↓@available(iOS 6, *)\nclass A {}",
+            "↓@available(iOS 6.0, macOS 10.12, *)\n class A {}",
+            "↓@available(macOS 10.12, iOS 6.0, *)\n class A {}",
+            "↓@available(macOS 10.7, *)\nclass A {}",
+            "↓@available(OSX 10.7, *)\nclass A {}",
+            "↓@available(watchOS 0.9, *)\nclass A {}",
+            "↓@available(tvOS 8, *)\nclass A {}",
+            "if ↓#available(iOS 6.0, *) {}",
+            "if ↓#available(iOS 6, *) {}",
+            "guard ↓#available(iOS 6.0, *) else { return }"
+        ]
+    )
+
+    public func validate(file: File) -> [StyleViolation] {
+        var violations = validateAttributes(file: file, dictionary: file.structure.dictionary)
+        violations += validateConditions(file: file)
+        violations.sort(by: { $0.location < $1.location })
+
+        return violations
+    }
+
+    private func validateConditions(file: File) -> [StyleViolation] {
+        let pattern = "#available\\s*\\([^\\(]+\\)"
+
+        return file.rangesAndTokens(matching: pattern).flatMap { range, tokens -> [StyleViolation] in
+            guard let availabilityToken = tokens.first,
+                SyntaxKind(rawValue: availabilityToken.type) == .keyword,
+                let tokenRange = file.contents.bridge().byteRangeToNSRange(start: availabilityToken.offset,
+                                                                           length: availabilityToken.length) else {
+                    return []
+            }
+
+            let rangeToSearch = NSRange(location: tokenRange.upperBound, length: range.length - tokenRange.length)
+            return validate(range: rangeToSearch, file: file, violationType: "condition",
+                            byteOffsetToReport: availabilityToken.offset)
+        }
+    }
+
+    private func validateAttributes(file: File, dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {
+        return dictionary.substructure.flatMap { subDict -> [StyleViolation] in
+            var violations = validateAttributes(file: file, dictionary: subDict)
+
+            if let kindString = subDict.kind,
+                let kind = SwiftDeclarationKind(rawValue: kindString) {
+                violations += validateAttributes(file: file, kind: kind, dictionary: subDict)
+            }
+
+            return violations
+        }
+    }
+
+    private func validateAttributes(file: File,
+                                    kind: SwiftDeclarationKind,
+                                    dictionary: [String: SourceKitRepresentable]) -> [StyleViolation] {
+        let attributes = dictionary.swiftAttributes.filter {
+            $0.attribute.flatMap(SwiftDeclarationAttributeKind.init) == .available
+        }
+        guard !attributes.isEmpty else {
+            return []
+        }
+
+        let contents = file.contents.bridge()
+        return attributes.flatMap { dictionary -> [StyleViolation] in
+            guard let offset = dictionary.offset, let length = dictionary.length,
+                let range = contents.byteRangeToNSRange(start: offset, length: length) else {
+                    return []
+            }
+
+            return validate(range: range, file: file, violationType: "attribute", byteOffsetToReport: offset)
+        }.unique
+    }
+
+    private func validate(range: NSRange, file: File, violationType: String,
+                          byteOffsetToReport: Int) -> [StyleViolation] {
+        let platformToConfiguredMinVersion = self.platformToConfiguredMinVersion
+        let allPlatforms = "(?:" + platformToConfiguredMinVersion.keys.joined(separator: "|") + ")"
+        let pattern = "\(allPlatforms) [\\d\\.]+"
+
+        return file.rangesAndTokens(matching: pattern, range: range).compactMap { _, tokens -> StyleViolation? in
+            guard tokens.count == 2,
+                tokens.kinds == [.keyword, .number],
+                let platform = file.contents(for: tokens[0]),
+                let minVersion = platformToConfiguredMinVersion[platform],
+                let versionString = file.contents(for: tokens[1]) else {
+                    return nil
+            }
+
+            guard let version = try? Version(rawValue: versionString),
+                version <= minVersion else {
+                    return nil
+            }
+
+            let reason = """
+            Availability \(violationType) is using a version (\(versionString)) that is \
+            satisfied by the deployment target (\(minVersion.stringValue)) for platform \(platform).
+            """
+            return StyleViolation(ruleDescription: type(of: self).description,
+                                  severity: configuration.severityConfiguration.severity,
+                                  location: Location(file: file, byteOffset: byteOffsetToReport),
+                                  reason: reason)
+        }
+    }
+
+    private var platformToConfiguredMinVersion: [String: Version] {
+        return [
+            "iOS": configuration.iOSDeploymentTarget,
+            "macOS": configuration.macOSDeploymentTarget,
+            "OSX": configuration.macOSDeploymentTarget,
+            "tvOS": configuration.tvOSDeploymentTarget,
+            "watchOS": configuration.watchOSDeploymentTarget
+        ]
+    }
+}
diff --git a/Source/SwiftLintFramework/Rules/RuleConfigurations/DeploymentTargetConfiguration.swift b/Source/SwiftLintFramework/Rules/RuleConfigurations/DeploymentTargetConfiguration.swift
new file mode 100644
index 0000000000..7c4e85b00d
--- /dev/null
+++ b/Source/SwiftLintFramework/Rules/RuleConfigurations/DeploymentTargetConfiguration.swift
@@ -0,0 +1,106 @@
+public struct DeploymentTargetConfiguration: RuleConfiguration, Equatable {
+    public struct Version: Equatable, Comparable {
+        public let major: Int
+        public let minor: Int
+        public let patch: Int
+
+        public var stringValue: String {
+            if patch > 0 {
+                return "\(major).\(minor).\(patch)"
+            } else {
+                return "\(major).\(minor)"
+            }
+        }
+
+        public init(major: Int, minor: Int = 0, patch: Int = 0) {
+            self.major = major
+            self.minor = minor
+            self.patch = patch
+        }
+
+        public init(rawValue: String) throws {
+            func parseNumber(_ string: String) throws -> Int {
+                guard let number = Int(string) else {
+                    throw ConfigurationError.unknownConfiguration
+                }
+                return number
+            }
+
+            let parts = rawValue.components(separatedBy: ".")
+            let count = parts.count
+            switch count {
+            case 0:
+                throw ConfigurationError.unknownConfiguration
+            case 1:
+                major = try parseNumber(parts[0])
+                minor = 0
+                patch = 0
+            case 2:
+                major = try parseNumber(parts[0])
+                minor = try parseNumber(parts[1])
+                patch = 0
+            default:
+                major = try parseNumber(parts[0])
+                minor = try parseNumber(parts[1])
+                patch = try parseNumber(parts[2])
+            }
+        }
+
+        fileprivate init(value: Any) throws {
+            if let version = value as? String {
+                try self.init(rawValue: version)
+            } else {
+                try self.init(rawValue: String(describing: value))
+            }
+        }
+
+        public static func < (lhs: Version, rhs: Version) -> Bool {
+            if lhs.major != rhs.major {
+                return lhs.major < rhs.major
+            } else if lhs.minor != rhs.minor {
+                return lhs.minor < rhs.minor
+            } else {
+                return lhs.patch < rhs.patch
+            }
+        }
+    }
+
+    private(set) var iOSDeploymentTarget = Version(major: 7)
+    private(set) var macOSDeploymentTarget = Version(major: 10, minor: 9)
+    private(set) var watchOSDeploymentTarget = Version(major: 1)
+    private(set) var tvOSDeploymentTarget = Version(major: 9)
+
+    private(set) var severityConfiguration = SeverityConfiguration(.warning)
+
+    public var consoleDescription: String {
+        return severityConfiguration.consoleDescription +
+            ", iOS_deployment_target: \(iOSDeploymentTarget.stringValue)" +
+            ", macOS_deployment_target: \(macOSDeploymentTarget.stringValue)" +
+            ", watchOS_deployment_target: \(watchOSDeploymentTarget.stringValue)" +
+            ", tvOS_deployment_target: \(tvOSDeploymentTarget.stringValue)"
+    }
+
+    public init() {}
+
+    public mutating func apply(configuration: Any) throws {
+        guard let configuration = configuration as? [String: Any] else {
+            throw ConfigurationError.unknownConfiguration
+        }
+        for (key, value) in configuration {
+            switch (key, value) {
+            case ("severity", let severityString as String):
+                try severityConfiguration.apply(configuration: severityString)
+            case ("iOS_deployment_target", let deploymentTarget):
+                self.iOSDeploymentTarget = try Version(value: deploymentTarget)
+            case ("macOS_deployment_target", let deploymentTarget):
+                self.macOSDeploymentTarget = try Version(value: deploymentTarget)
+            case ("watchOS_deployment_target", let deploymentTarget):
+                self.watchOSDeploymentTarget = try Version(value: deploymentTarget)
+            case ("tvOS_deployment_target", let deploymentTarget):
+                self.tvOSDeploymentTarget = try Version(value: deploymentTarget)
+            default:
+                throw ConfigurationError.unknownConfiguration
+            }
+        }
+    }
+}
diff --git a/SwiftLint.xcodeproj/project.pbxproj b/SwiftLint.xcodeproj/project.pbxproj
index c7f9bdfb93..2046cc0e05 100644
--- a/SwiftLint.xcodeproj/project.pbxproj
+++ b/SwiftLint.xcodeproj/project.pbxproj
@@ -228,6 +228,10 @@
 		D414D6AC21D0B77F00960935 /* DiscouragedObjectLiteralRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D414D6AB21D0B77F00960935 /* DiscouragedObjectLiteralRuleTests.swift */; };
 		D414D6AE21D22FF500960935 /* LastWhereRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D414D6AD21D22FF500960935 /* LastWhereRule.swift */; };
 		D41985E721F85014003BE2B7 /* NSLocalizedStringKeyRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41985E621F85014003BE2B7 /* NSLocalizedStringKeyRule.swift */; };
+		D41985E921FAB62F003BE2B7 /* DeploymentTargetRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41985E821FAB62F003BE2B7 /* DeploymentTargetRule.swift */; };
+		D41985EB21FAB63E003BE2B7 /* DeploymentTargetConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41985EA21FAB63E003BE2B7 /* DeploymentTargetConfiguration.swift */; };
+		D41985ED21FAD033003BE2B7 /* DeploymentTargetConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41985EC21FAD033003BE2B7 /* DeploymentTargetConfigurationTests.swift */; };
+		D41985EF21FAD5E8003BE2B7 /* DeploymentTargetRuleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41985EE21FAD5E8003BE2B7 /* DeploymentTargetRuleTests.swift */; };
 		D41B57781ED8CEE0007B0470 /* ExtensionAccessModifierRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41B57771ED8CEE0007B0470 /* ExtensionAccessModifierRule.swift */; };
 		D41E7E0B1DF9DABB0065259A /* RedundantStringEnumValueRule.swift in Sources */ = {isa = PBXBuildFile; fileRef = D41E7E0A1DF9DABB0065259A /* RedundantStringEnumValueRule.swift */; };
 		D4246D6D1F30D8620097E658 /* PrivateOverFilePrivateRuleConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4246D6C1F30D8620097E658 /* PrivateOverFilePrivateRuleConfiguration.swift */; };
@@ -690,6 +694,10 @@
 		D414D6AB21D0B77F00960935 /* DiscouragedObjectLiteralRuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscouragedObjectLiteralRuleTests.swift; sourceTree = "<group>"; };
 		D414D6AD21D22FF500960935 /* LastWhereRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LastWhereRule.swift; sourceTree = "<group>"; };
 		D41985E621F85014003BE2B7 /* NSLocalizedStringKeyRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLocalizedStringKeyRule.swift; sourceTree = "<group>"; };
+		D41985E821FAB62F003BE2B7 /* DeploymentTargetRule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeploymentTargetRule.swift; sourceTree = "<group>"; };
+		D41985EA21FAB63E003BE2B7 /* DeploymentTargetConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeploymentTargetConfiguration.swift; sourceTree = "<group>"; };
+		D41985EC21FAD033003BE2B7 /* DeploymentTargetConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeploymentTargetConfigurationTests.swift; sourceTree = "<group>"; };
+		D41985EE21FAD5E8003BE2B7 /* DeploymentTargetRuleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeploymentTargetRuleTests.swift; sourceTree = "<group>"; };
 		D41B57771ED8CEE0007B0470 /* ExtensionAccessModifierRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtensionAccessModifierRule.swift; sourceTree = "<group>"; };
 		D41E7E0A1DF9DABB0065259A /* RedundantStringEnumValueRule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RedundantStringEnumValueRule.swift; sourceTree = "<group>"; };
 		D4246D6C1F30D8620097E658 /* PrivateOverFilePrivateRuleConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PrivateOverFilePrivateRuleConfiguration.swift; sourceTree = "<group>"; };
@@ -930,6 +938,7 @@
 				824AB64C2105C39F004B5A8F /* ConditionalReturnsOnNewlineConfiguration.swift */,
 				67EB4DF81E4CC101004E9ACD /* CyclomaticComplexityConfiguration.swift */,
 				62A498551F306A7700D766E4 /* DiscouragedDirectInitConfiguration.swift */,
+				D41985EA21FAB63E003BE2B7 /* DeploymentTargetConfiguration.swift */,
 				125AAC77203AA82D0004BCE0 /* ExplicitTypeInterfaceConfiguration.swift */,
 				D4C4A3511DEFBBB700E0E04C /* FileHeaderConfiguration.swift */,
 				29FFC3781F1574FD007E4825 /* FileLengthRuleConfiguration.swift */,
@@ -1024,6 +1033,7 @@
 				D4B0228D1E0CC608007E5297 /* ClassDelegateProtocolRule.swift */,
 				D4DA1DF31E17511D0037413D /* CompilerProtocolInitRule.swift */,
 				D4DABFD21E29B4A5009617B6 /* DiscardedNotificationCenterObserverRule.swift */,
+				D41985E821FAB62F003BE2B7 /* DeploymentTargetRule.swift */,
 				62622F6A1F2F2E3500D5D099 /* DiscouragedDirectInitRule.swift */,
 				E315B83B1DFA4BC500621B44 /* DynamicInlineRule.swift */,
 				62A3E95B209E078000547A86 /* EmptyXCTestMethodRule.swift */,
@@ -1359,6 +1369,8 @@
 				67932E2C1E54AF4B00CB0629 /* CyclomaticComplexityConfigurationTests.swift */,
 				67EB4DFB1E4CD7F5004E9ACD /* CyclomaticComplexityRuleTests.swift */,
 				CCD8B87720559C4A00B75847 /* DisableAllTests.swift */,
+				D41985EC21FAD033003BE2B7 /* DeploymentTargetConfigurationTests.swift */,
+				D41985EE21FAD5E8003BE2B7 /* DeploymentTargetRuleTests.swift */,
 				62AF35D71F30B183009B11EE /* DiscouragedDirectInitRuleTests.swift */,
 				D48B51221F4F5E4B0068AB98 /* DocumentationTests.swift */,
 				D414D6AB21D0B77F00960935 /* DiscouragedObjectLiteralRuleTests.swift */,
@@ -1993,6 +2005,7 @@
 				D4DA1DF41E17511D0037413D /* CompilerProtocolInitRule.swift in Sources */,
 				629C60D91F43906700B4AF92 /* SingleTestClassRule.swift in Sources */,
 				621061BF1ED57E640082D51E /* MultilineParametersRuleExamples.swift in Sources */,
+				D41985EB21FAB63E003BE2B7 /* DeploymentTargetConfiguration.swift in Sources */,
 				D48AE2CC1DFB58C5001C6A4A /* AttributesRuleExamples.swift in Sources */,
 				C28B2B3D2106DF730009A0FE /* PrefixedConstantRuleConfiguration.swift in Sources */,
 				62A7127520F1178F00E604A6 /* AnyObjectProtocolRule.swift in Sources */,
@@ -2066,6 +2079,7 @@
 				4A9A3A3A1DC1D75F00DF5183 /* HTMLReporter.swift in Sources */,
 				D40F83881DE9179200524C62 /* TrailingCommaConfiguration.swift in Sources */,
 				827169B31F488181003FB9AF /* ExplicitEnumRawValueRule.swift in Sources */,
+				D41985E921FAB62F003BE2B7 /* DeploymentTargetRule.swift in Sources */,
 				62FE5D32200CABDD00F68793 /* DiscouragedOptionalCollectionExamples.swift in Sources */,
 				D49896F12026B36C00814A83 /* RedundantSetAccessControlRule.swift in Sources */,
 				29FFC37A1F15764D007E4825 /* FileLengthRuleConfiguration.swift in Sources */,
@@ -2116,6 +2130,7 @@
 				D4F5851520E99A8A0085C6D8 /* TrailingWhitespaceTests.swift in Sources */,
 				D450D1E021F19AB300E60010 /* TrailingClosureRuleTests.swift in Sources */,
 				3B12C9C31C320A53000B423F /* YamlSwiftLintTests.swift in Sources */,
+				D41985ED21FAD033003BE2B7 /* DeploymentTargetConfigurationTests.swift in Sources */,
 				D450D1E221F19B1E00E60010 /* TrailingClosureConfigurationTests.swift in Sources */,
 				E832F10D1B17E725003F265F /* IntegrationTests.swift in Sources */,
 				D4C27C001E12DFF500DF713E /* LinterCacheTests.swift in Sources */,
@@ -2136,6 +2151,7 @@
 				D4348EEA1C46122C007707FB /* FunctionBodyLengthRuleTests.swift in Sources */,
 				F480DC831F2609D700099465 /* ConfigurationTests+ProjectMock.swift in Sources */,
 				3B63D46D1E1F05160057BE35 /* LineLengthConfigurationTests.swift in Sources */,
+				D41985EF21FAD5E8003BE2B7 /* DeploymentTargetRuleTests.swift in Sources */,
 				6C7045441C6ADA450003F15A /* SourceKitCrashTests.swift in Sources */,
 				820F451E21073D7200AA056A /* ConditionalReturnsOnNewlineRuleTests.swift in Sources */,
 				D4246D6F1F30DB260097E658 /* PrivateOverFilePrivateRuleTests.swift in Sources */,
diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift
index ae322bd04c..d445026beb 100644
--- a/Tests/LinuxMain.swift
+++ b/Tests/LinuxMain.swift
@@ -232,6 +232,21 @@ extension CyclomaticComplexityRuleTests {
     ]
 }
 
+extension DeploymentTargetConfigurationTests {
+    static var allTests: [(String, (DeploymentTargetConfigurationTests) -> () throws -> Void)] = [
+        ("testAppliesConfigurationFromDictionary", testAppliesConfigurationFromDictionary),
+        ("testThrowsOnBadConfig", testThrowsOnBadConfig)
+    ]
+}
+
+extension DeploymentTargetRuleTests {
+    static var allTests: [(String, (DeploymentTargetRuleTests) -> () throws -> Void)] = [
+        ("testRule", testRule),
+        ("testMacOSAttributeReason", testMacOSAttributeReason),
+        ("testWatchOSConditionReason", testWatchOSConditionReason)
+    ]
+}
+
 extension DisableAllTests {
     static var allTests: [(String, (DisableAllTests) -> () throws -> Void)] = [
         ("testViolatingPhrase", testViolatingPhrase),
@@ -1457,6 +1472,8 @@ XCTMain([
     testCase(CustomRulesTests.allTests),
     testCase(CyclomaticComplexityConfigurationTests.allTests),
     testCase(CyclomaticComplexityRuleTests.allTests),
+    testCase(DeploymentTargetConfigurationTests.allTests),
+    testCase(DeploymentTargetRuleTests.allTests),
     testCase(DisableAllTests.allTests),
     testCase(DiscardedNotificationCenterObserverRuleTests.allTests),
     testCase(DiscouragedDirectInitRuleTests.allTests),
diff --git a/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift b/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift
new file mode 100644
index 0000000000..9bc76f4ebc
--- /dev/null
+++ b/Tests/SwiftLintFrameworkTests/DeploymentTargetConfigurationTests.swift
@@ -0,0 +1,50 @@
+import SourceKittenFramework
+@testable import SwiftLintFramework
+import XCTest
+
+class DeploymentTargetConfigurationTests: XCTestCase {
+    typealias Version = DeploymentTargetConfiguration.Version
+
+    func testAppliesConfigurationFromDictionary() throws {
+        var configuration = DeploymentTargetConfiguration()
+
+        try configuration.apply(configuration: ["iOS_deployment_target": "10.1", "severity": "error"])
+        XCTAssertEqual(configuration.iOSDeploymentTarget, Version(major: 10, minor: 1))
+        XCTAssertEqual(configuration.severityConfiguration.severity, .error)
+
+        try configuration.apply(configuration: ["macOS_deployment_target": "10.11.3"])
+        XCTAssertEqual(configuration.iOSDeploymentTarget, Version(major: 10, minor: 1))
+        XCTAssertEqual(configuration.macOSDeploymentTarget, Version(major: 10, minor: 11, patch: 3))
+        XCTAssertEqual(configuration.severityConfiguration.severity, .error)
+
+        try configuration.apply(configuration: ["severity": "warning"])
+        XCTAssertEqual(configuration.iOSDeploymentTarget, Version(major: 10, minor: 1))
+        XCTAssertEqual(configuration.macOSDeploymentTarget, Version(major: 10, minor: 11, patch: 3))
+        XCTAssertEqual(configuration.severityConfiguration.severity, .warning)
+
+        try configuration.apply(configuration: ["tvOS_deployment_target": 10.2,
+                                                "watchOS_deployment_target": 5])
+        XCTAssertEqual(configuration.iOSDeploymentTarget, Version(major: 10, minor: 1))
+        XCTAssertEqual(configuration.macOSDeploymentTarget, Version(major: 10, minor: 11, patch: 3))
+        XCTAssertEqual(configuration.tvOSDeploymentTarget, Version(major: 10, minor: 2))
+        XCTAssertEqual(configuration.watchOSDeploymentTarget, Version(major: 5))
+        XCTAssertEqual(configuration.severityConfiguration.severity, .warning)
+    }
+
+    func testThrowsOnBadConfig() {
+        let badConfigs: [[String: Any]] = [
+            ["iOS_deployment_target": "foo"],
+            ["iOS_deployment_target": ""],
+            ["iOS_deployment_target": "5.x"],
+            ["iOS_deployment_target": true],
+            ["invalid": true]
+        ]
+
+        for badConfig in badConfigs {
+            var configuration = DeploymentTargetConfiguration()
+            checkError(ConfigurationError.unknownConfiguration) {
+                try configuration.apply(configuration: badConfig)
+            }
+        }
+    }
+}
diff --git a/Tests/SwiftLintFrameworkTests/DeploymentTargetRuleTests.swift b/Tests/SwiftLintFrameworkTests/DeploymentTargetRuleTests.swift
new file mode 100644
index 0000000000..3ff0af26ae
--- /dev/null
+++ b/Tests/SwiftLintFrameworkTests/DeploymentTargetRuleTests.swift
@@ -0,0 +1,38 @@
+import SwiftLintFramework
+import XCTest
+
+class DeploymentTargetRuleTests: XCTestCase {
+    func testRule() {
+        verifyRule(DeploymentTargetRule.description)
+    }
+
+    // MARK: - Reasons
+
+    func testMacOSAttributeReason() {
+        let string = "@availability(macOS 10.11, *)\nclass A {}"
+        let violations = self.violations(string, config: ["macOS_deployment_target": "10.14.0"])
+
+        let expectedMessage = "Availability attribute is using a version (10.11) that is satisfied by " +
+                              "the deployment target (10.14) for platform macOS."
+        XCTAssertEqual(violations.count, 1)
+        XCTAssertEqual(violations.first?.reason, expectedMessage)
+    }
+
+    func testWatchOSConditionReason() {
+        let string = "if #available(watchOS 4, *) {}"
+        let violations = self.violations(string, config: ["watchOS_deployment_target": "5.0.1"])
+
+        let expectedMessage = "Availability condition is using a version (4) that is satisfied by " +
+                              "the deployment target (5.0.1) for platform watchOS."
+        XCTAssertEqual(violations.count, 1)
+        XCTAssertEqual(violations.first?.reason, expectedMessage)
+    }
+
+    private func violations(_ string: String, config: Any?) -> [StyleViolation] {
+        guard let config = makeConfig(config, DeploymentTargetRule.description.identifier) else {
+            return []
+        }
+
+        return SwiftLintFrameworkTests.violations(string, config: config)
+    }
+}