diff --git a/src/ipa/rkisp1/algorithms/dpf.cpp b/src/ipa/rkisp1/algorithms/dpf.cpp
index c232f2ad..174c4160 100644
--- a/src/ipa/rkisp1/algorithms/dpf.cpp
+++ b/src/ipa/rkisp1/algorithms/dpf.cpp
@@ -551,6 +551,48 @@ bool Dpf::parseControls(const ControlList &controls)
 	return true;
 }
 
+void Dpf::fillMetadata([[maybe_unused]] IPAContext &context, [[maybe_unused]] IPAFrameContext &frameContext, ControlList &metadata)
+{
+	/* Strength (R,G,B) */
+	std::array<int32_t, 3> strength{ activeMode_->strength.r, activeMode_->strength.g, activeMode_->strength.b };
+	metadata.set(controls::rkisp1::DpfChannelStrengths, Span<const int32_t, 3>(strength));
+
+	/* Spatial kernels */
+	std::array<int32_t, RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS> greenCoeffs;
+	std::copy(std::begin(activeMode_->dpf.g_flt.spatial_coeff), std::end(activeMode_->dpf.g_flt.spatial_coeff), greenCoeffs.begin());
+	metadata.set(controls::rkisp1::DpfGreenSpatialCoefficients,
+		     Span<const int32_t, RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS>(greenCoeffs));
+
+	std::array<int32_t, RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS> redBlueCoeffs;
+	std::copy(std::begin(activeMode_->dpf.rb_flt.spatial_coeff), std::end(activeMode_->dpf.rb_flt.spatial_coeff), redBlueCoeffs.begin());
+	metadata.set(controls::rkisp1::DpfRedBlueSpatialCoefficients,
+		     Span<const int32_t, RKISP1_CIF_ISP_DPF_MAX_SPATIAL_COEFFS>(redBlueCoeffs));
+
+	metadata.set(controls::rkisp1::DpfRedBlueFilterSize,
+		     static_cast<int32_t>(activeMode_->dpf.rb_flt.fltsize));
+
+	/* NLL coefficients and scale */
+	std::array<int32_t, RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS> nllCoeffs;
+	std::copy(std::begin(activeMode_->dpf.nll.coeff), std::end(activeMode_->dpf.nll.coeff), nllCoeffs.begin());
+	metadata.set(controls::rkisp1::DpfNoiseLevelLookupCoefficients,
+		     Span<const int32_t, RKISP1_CIF_ISP_DPF_MAX_NLF_COEFFS>(nllCoeffs));
+	metadata.set(controls::rkisp1::DpfNoiseLevelLookupScaleMode, activeMode_->dpf.nll.scale_mode);
+}
+
+/**
+ * \copydoc libcamera::ipa::Algorithm::process
+ */
+void Dpf::process(IPAContext &context, const uint32_t frame [[maybe_unused]],
+		  IPAFrameContext &frameContext,
+		  const rkisp1_stat_buffer *stats [[maybe_unused]],
+		  ControlList &metadata)
+{
+	if (noiseReductionModes_.empty())
+		return;
+
+	fillMetadata(context, frameContext, metadata);
+}
+
 REGISTER_IPA_ALGORITHM(Dpf, "Dpf")
 
 } /* namespace ipa::rkisp1::algorithms */
diff --git a/src/ipa/rkisp1/algorithms/dpf.h b/src/ipa/rkisp1/algorithms/dpf.h
index e3dea97b..62f5e2f7 100644
--- a/src/ipa/rkisp1/algorithms/dpf.h
+++ b/src/ipa/rkisp1/algorithms/dpf.h
@@ -28,6 +28,10 @@ public:
 	void prepare(IPAContext &context, const uint32_t frame,
 		     IPAFrameContext &frameContext,
 		     RkISP1Params *params) override;
+	void process(IPAContext &context, const uint32_t frame,
+		     IPAFrameContext &frameContext,
+		     const rkisp1_stat_buffer *stats,
+		     ControlList &metadata) override;
 
 private:
 	struct ModeConfig {
@@ -51,6 +55,8 @@ private:
 	void prepareDisabledMode(RkISP1Params *params);
 	void prepareEnabledMode(IPAContext &context, IPAFrameContext &frameContext,
 				RkISP1Params *params);
+	void fillMetadata(IPAContext &context, IPAFrameContext &frameContext,
+			  ControlList &metadata);
 
 	std::vector<ModeConfig> noiseReductionModes_;
 	std::vector<ModeConfig>::const_iterator activeMode_;
