diff --git a/src/android/camera_capabilities.cpp b/src/android/camera_capabilities.cpp
index 08e44a1a..be6687d9 100644
--- a/src/android/camera_capabilities.cpp
+++ b/src/android/camera_capabilities.cpp
@@ -375,6 +375,25 @@ void CameraCapabilities::computeHwLevel(
 	if (!found || *entry.data.i32 != 0)
 		hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
 
+	found = staticMetadata_->entryContains<uint8_t>(
+		ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
+		ANDROID_NOISE_REDUCTION_MODE_OFF);
+	if (!found)
+		hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
+
+	found = staticMetadata_->entryContains<uint8_t>(
+		ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
+		ANDROID_NOISE_REDUCTION_MODE_FAST);
+	if (!found)
+		hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
+
+	/* Android docs don't say this is required, but CTS does. */
+	found = staticMetadata_->entryContains<uint8_t>(
+		ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES,
+		ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY);
+	if (!found)
+		hwLevel = ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED;
+
 	hwLevel_ = hwLevel;
 }
 
diff --git a/src/android/camera_device.cpp b/src/android/camera_device.cpp
index ab31bdda..502dd10a 100644
--- a/src/android/camera_device.cpp
+++ b/src/android/camera_device.cpp
@@ -826,6 +826,40 @@ int CameraDevice::processControls(Camera3RequestDescriptor *descriptor)
 		controls.set(controls::draft::TestPatternMode, testPatternMode);
 	}
 
+	if (settings.getEntry(ANDROID_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES, &entry)) {
+		const uint8_t data = *entry.data.u8;
+		int32_t noiseReductionMode = controls::NoiseReductionModeOff;
+		switch (data) {
+		case ANDROID_NOISE_REDUCTION_MODE_OFF:
+			noiseReductionMode = controls::NoiseReductionModeOff;
+			break;
+
+		case ANDROID_NOISE_REDUCTION_MODE_FAST:
+			noiseReductionMode = controls::NoiseReductionModeFast;
+			break;
+
+		case ANDROID_NOISE_REDUCTION_MODE_HIGH_QUALITY:
+			noiseReductionMode = controls::NoiseReductionModeHighQuality;
+			break;
+
+		case ANDROID_NOISE_REDUCTION_MODE_MINIMAL:
+			noiseReductionMode = controls::NoiseReductionModeRaw;
+			break;
+
+		case ANDROID_NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG:
+			noiseReductionMode = controls::NoiseReductionModeZSL;
+			break;
+
+		default:
+			LOG(HAL, Error)
+				<< "Unknown noise reduction mode: " << data;
+
+			return -EINVAL;
+		}
+
+		controls.set(controls::NoiseReductionMode, noiseReductionMode);
+	}
+
 	return 0;
 }
 
@@ -1379,6 +1413,13 @@ CameraDevice::getResultMetadata(const Camera3RequestDescriptor &descriptor) cons
 		resultMetadata->addEntry(ANDROID_SCALER_CROP_REGION, cropRect);
 	}
 
+	if (metadata.contains(controls::NoiseReductionMode)) {
+		const int32_t noiseReductionMode =
+			metadata.get(controls::NoiseReductionMode);
+		resultMetadata->addEntry(ANDROID_NOISE_REDUCTION_MODE,
+					 noiseReductionMode);
+	}
+
 	if (metadata.contains(controls::draft::TestPatternMode)) {
 		const int32_t testPatternMode =
 			metadata.get(controls::draft::TestPatternMode);
