diff --git a/include/libcamera/internal/software_isp/software_isp.h b/include/libcamera/internal/software_isp/software_isp.h
index b8b24bb1b..4491226ce 100644
--- a/include/libcamera/internal/software_isp/software_isp.h
+++ b/include/libcamera/internal/software_isp/software_isp.h
@@ -87,11 +87,11 @@ public:
 	Signal<FrameBuffer *> outputBufferReady;
 	Signal<uint32_t, uint32_t> ispStatsReady;
 	Signal<uint32_t, const ControlList &> metadataReady;
-	Signal<const ControlList &> setSensorControls;
+	Signal<const ControlList &, const ControlList &> setSensorControls;
 
 private:
 	void saveIspParams(uint32_t frame);
-	void setSensorCtrls(const ControlList &sensorControls);
+	void setSensorCtrls(const ControlList &sensorControls, const ControlList &lensControls);
 	void statsReady(uint32_t frame, uint32_t bufferId);
 	void inputReady(FrameBuffer *input);
 	void outputReady(FrameBuffer *output);
diff --git a/include/libcamera/ipa/softisp.mojom b/include/libcamera/ipa/softisp.mojom
index 209af1fde..37b8c0f11 100644
--- a/include/libcamera/ipa/softisp.mojom
+++ b/include/libcamera/ipa/softisp.mojom
@@ -10,6 +10,7 @@ import "include/libcamera/ipa/core.mojom";
 
 struct IPAConfigInfo {
 	libcamera.ControlInfoMap sensorControls;
+	libcamera.ControlInfoMap lensControls;
 };
 
 interface IPASoftIspInterface {
@@ -32,7 +33,7 @@ interface IPASoftIspInterface {
 };
 
 interface IPASoftIspEventInterface {
-	setSensorControls(libcamera.ControlList sensorControls);
+	setSensorControls(libcamera.ControlList sensorControls, libcamera.ControlList lensControls);
 	paramsComputed(uint32 frame);
 	metadataReady(uint32 frame, libcamera.ControlList metadata);
 };
diff --git a/src/ipa/softisp/ipa_context.h b/src/ipa/softisp/ipa_context.h
index 8546dedd8..8e9ef3850 100644
--- a/src/ipa/softisp/ipa_context.h
+++ b/src/ipa/softisp/ipa_context.h
@@ -80,6 +80,7 @@ struct IPAContext {
 
 	IPACameraSensorInfo sensorInfo;
 	ControlInfoMap sensorControls;
+	ControlInfoMap lensControls;
 	std::unique_ptr<CameraSensorHelper> camHelper;
 	IPASessionConfiguration configuration;
 	IPAActiveState activeState;
diff --git a/src/ipa/softisp/softisp.cpp b/src/ipa/softisp/softisp.cpp
index 8acfcd1a0..daee794b2 100644
--- a/src/ipa/softisp/softisp.cpp
+++ b/src/ipa/softisp/softisp.cpp
@@ -187,6 +187,7 @@ int IPASoftIsp::init(const IPASettings &settings,
 int IPASoftIsp::configure(const IPAConfigInfo &configInfo, ControlInfoMap *ipaControls)
 {
 	context_.sensorControls = configInfo.sensorControls;
+	context_.lensControls = configInfo.lensControls;
 
 	/* Clear the IPA context before the streaming session. */
 	context_.configuration = {};
@@ -251,7 +252,11 @@ void IPASoftIsp::processStats(const uint32_t frame,
 	ControlList ctrls(context_.sensorControls);
 	agc::prepareControls(ctrls, context_.camHelper.get(),
 			     frameContext.agc.exposure, frameContext.agc.gain);
-	setSensorControls.emit(ctrls);
+	ControlList lensCtrls(context_.lensControls);
+	if (context_.afEnabled)
+		lensCtrls.set(V4L2_CID_FOCUS_ABSOLUTE,
+			      static_cast<int32_t>(context_.activeState.af.focus));
+	setSensorControls.emit(ctrls, lensCtrls);
 }
 
 std::string IPASoftIsp::logPrefix() const
diff --git a/src/libcamera/pipeline/simple/simple.cpp b/src/libcamera/pipeline/simple/simple.cpp
index 35c29ceca..a55672cb4 100644
--- a/src/libcamera/pipeline/simple/simple.cpp
+++ b/src/libcamera/pipeline/simple/simple.cpp
@@ -33,6 +33,7 @@
 #include <libcamera/stream.h>
 
 #include "libcamera/internal/camera.h"
+#include "libcamera/internal/camera_lens.h"
 #include "libcamera/internal/camera_manager.h"
 #include "libcamera/internal/camera_sensor.h"
 #include "libcamera/internal/camera_sensor_properties.h"
@@ -371,7 +372,7 @@ private:
 
 	void ispStatsReady(uint32_t frame, uint32_t bufferId);
 	void metadataReady(uint32_t frame, const ControlList &metadata);
-	void setSensorControls(const ControlList &sensorControls);
+	void setSensorControls(const ControlList &sensorControls, const ControlList &lensControls);
 };
 
 class SimpleCameraConfiguration : public CameraConfiguration
@@ -1041,7 +1042,7 @@ void SimpleCameraData::metadataReady(uint32_t frame, const ControlList &metadata
 	tryCompleteRequest(info->request);
 }
 
-void SimpleCameraData::setSensorControls(const ControlList &sensorControls)
+void SimpleCameraData::setSensorControls(const ControlList &sensorControls, const ControlList &lensControls)
 {
 	delayedCtrls_->push(sensorControls);
 	/*
@@ -1055,6 +1056,12 @@ void SimpleCameraData::setSensorControls(const ControlList &sensorControls)
 	if (!frameStartEmitter_) {
 		ControlList ctrls(sensorControls);
 		sensor_->setControls(&ctrls);
+
+		CameraLens *lens = sensor_->focusLens();
+		if (lens && lensControls.contains(V4L2_CID_FOCUS_ABSOLUTE)) {
+			ControlValue const &focusValue = lensControls.get(V4L2_CID_FOCUS_ABSOLUTE);
+			lens->setFocusPosition(focusValue.get<int32_t>());
+		}
 	}
 }
 
@@ -1605,6 +1612,8 @@ int SimplePipelineHandler::configure(Camera *camera, CameraConfiguration *c)
 	} else {
 		ipa::softisp::IPAConfigInfo configInfo;
 		configInfo.sensorControls = data->sensor_->controls();
+		if (data->sensor_->focusLens())
+			configInfo.lensControls = data->sensor_->focusLens()->controls();
 		return data->swIsp_->configure(inputCfg, outputCfgs, configInfo, &data->controlInfo_);
 	}
 }
diff --git a/src/libcamera/software_isp/software_isp.cpp b/src/libcamera/software_isp/software_isp.cpp
index a40976055..c10445d72 100644
--- a/src/libcamera/software_isp/software_isp.cpp
+++ b/src/libcamera/software_isp/software_isp.cpp
@@ -442,9 +442,9 @@ void SoftwareIsp::saveIspParams([[maybe_unused]] uint32_t frame)
 	debayerParams_ = *sharedParams_;
 }
 
-void SoftwareIsp::setSensorCtrls(const ControlList &sensorControls)
+void SoftwareIsp::setSensorCtrls(const ControlList &sensorControls, const ControlList &lensControls)
 {
-	setSensorControls.emit(sensorControls);
+	setSensorControls.emit(sensorControls, lensControls);
 }
 
 void SoftwareIsp::statsReady(uint32_t frame, uint32_t bufferId)
