diff --git a/include/libcamera/ipa/ipu3.mojom b/include/libcamera/ipa/ipu3.mojom
index d1b1c6b867da..5818cd3a6846 100644
--- a/include/libcamera/ipa/ipu3.mojom
+++ b/include/libcamera/ipa/ipu3.mojom
@@ -18,14 +18,13 @@ struct IPAConfigInfo {
 
 interface IPAIPU3Interface {
 	init(libcamera.IPASettings settings,
-	     libcamera.IPACameraSensorInfo sensorInfo,
-	     libcamera.ControlInfoMap sensorControls)
-		=> (int32 ret, libcamera.ControlInfoMap ipaControls);
+	     libcamera.IPACameraSensorInfo sensorInfo)
+		=> (int32 ret);
 	start() => (int32 ret);
 	stop();
 
 	configure(IPAConfigInfo configInfo)
-		=> (int32 ret, libcamera.ControlInfoMap ipaControls);
+		=> (int32 ret);
 
 	mapBuffers(array<libcamera.IPABuffer> buffers);
 	unmapBuffers(array<uint32> ids);
diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
index 2f6bb672f7bb..a6e5dcbaada9 100644
--- a/src/ipa/ipu3/ipu3.cpp
+++ b/src/ipa/ipu3/ipu3.cpp
@@ -132,15 +132,12 @@ class IPAIPU3 : public IPAIPU3Interface
 {
 public:
 	int init(const IPASettings &settings,
-		 const IPACameraSensorInfo &sensorInfo,
-		 const ControlInfoMap &sensorControls,
-		 ControlInfoMap *ipaControls) override;
+		 const IPACameraSensorInfo &sensorInfo) override;
 
 	int start() override;
 	void stop() override;
 
-	int configure(const IPAConfigInfo &configInfo,
-		      ControlInfoMap *ipaControls) override;
+	int configure(const IPAConfigInfo &configInfo) override;
 
 	void mapBuffers(const std::vector<IPABuffer> &buffers) override;
 	void unmapBuffers(const std::vector<unsigned int> &ids) override;
@@ -151,9 +148,6 @@ public:
 				const uint32_t bufferId,
 				const ControlList &sensorControls) override;
 private:
-	void updateControls(const IPACameraSensorInfo &sensorInfo,
-			    const ControlInfoMap &sensorControls,
-			    ControlInfoMap *ipaControls);
 	void updateSessionConfiguration(const ControlInfoMap &sensorControls);
 
 	bool validateSensorControls();
@@ -208,68 +202,6 @@ void IPAIPU3::updateSessionConfiguration(const ControlInfoMap &sensorControls)
 	context_.configuration.agc.maxAnalogueGain = camHelper_->gain(maxGain);
 }
 
-/**
- * \brief Compute camera controls using the sensor information and the sensor
- * V4L2 controls
- *
- * Some of the camera controls are computed by the pipeline handler, some others
- * by the IPA module which is in charge of handling, for example, the exposure
- * time and the frame duration.
- *
- * This function computes:
- * - controls::ExposureTime
- * - controls::FrameDurationLimits
- */
-void IPAIPU3::updateControls(const IPACameraSensorInfo &sensorInfo,
-			     const ControlInfoMap &sensorControls,
-			     ControlInfoMap *ipaControls)
-{
-	ControlInfoMap::Map controls{};
-	double lineDuration = context_.configuration.sensor.lineDuration.get<std::micro>();
-
-	/*
-	 * Compute exposure time limits by using line length and pixel rate
-	 * converted to microseconds. Use the V4L2_CID_EXPOSURE control to get
-	 * exposure min, max and default and convert it from lines to
-	 * microseconds.
-	 */
-	const ControlInfo &v4l2Exposure = sensorControls.find(V4L2_CID_EXPOSURE)->second;
-	int32_t minExposure = v4l2Exposure.min().get<int32_t>() * lineDuration;
-	int32_t maxExposure = v4l2Exposure.max().get<int32_t>() * lineDuration;
-	int32_t defExposure = v4l2Exposure.def().get<int32_t>() * lineDuration;
-	controls[&controls::ExposureTime] = ControlInfo(minExposure, maxExposure,
-							defExposure);
-
-	/*
-	 * Compute the frame duration limits.
-	 *
-	 * The frame length is computed assuming a fixed line length combined
-	 * with the vertical frame sizes.
-	 */
-	const ControlInfo &v4l2HBlank = sensorControls.find(V4L2_CID_HBLANK)->second;
-	uint32_t hblank = v4l2HBlank.def().get<int32_t>();
-	uint32_t lineLength = sensorInfo.outputSize.width + hblank;
-
-	const ControlInfo &v4l2VBlank = sensorControls.find(V4L2_CID_VBLANK)->second;
-	std::array<uint32_t, 3> frameHeights{
-		v4l2VBlank.min().get<int32_t>() + sensorInfo.outputSize.height,
-		v4l2VBlank.max().get<int32_t>() + sensorInfo.outputSize.height,
-		v4l2VBlank.def().get<int32_t>() + sensorInfo.outputSize.height,
-	};
-
-	std::array<int64_t, 3> frameDurations;
-	for (unsigned int i = 0; i < frameHeights.size(); ++i) {
-		uint64_t frameSize = lineLength * frameHeights[i];
-		frameDurations[i] = frameSize / (sensorInfo.pixelRate / 1000000U);
-	}
-
-	controls[&controls::FrameDurationLimits] = ControlInfo(frameDurations[0],
-							       frameDurations[1],
-							       frameDurations[2]);
-
-	*ipaControls = ControlInfoMap(std::move(controls), controls::controls);
-}
-
 /**
  * \brief Validate that the sensor controls mandatory for the IPA exists
  */
@@ -300,9 +232,7 @@ bool IPAIPU3::validateSensorControls()
  * them in the \a ipaControls output parameter.
  */
 int IPAIPU3::init(const IPASettings &settings,
-		  const IPACameraSensorInfo &sensorInfo,
-		  const ControlInfoMap &sensorControls,
-		  ControlInfoMap *ipaControls)
+		  const IPACameraSensorInfo &sensorInfo)
 {
 	camHelper_ = CameraSensorHelperFactory::create(settings.sensorModel);
 	if (camHelper_ == nullptr) {
@@ -323,9 +253,6 @@ int IPAIPU3::init(const IPASettings &settings,
 	algorithms_.push_back(std::make_unique<algorithms::BlackLevelCorrection>());
 	algorithms_.push_back(std::make_unique<algorithms::ToneMapping>());
 
-	/* Initialize controls. */
-	updateControls(sensorInfo, sensorControls, ipaControls);
-
 	return 0;
 }
 
@@ -423,7 +350,6 @@ void IPAIPU3::calculateBdsGrid(const Size &bdsOutputSize)
  * \brief Configure the IPU3 IPA
  * \param[in] configInfo The IPA configuration data, received from the pipeline
  * handler
- * \param[in] ipaControls The IPA controls to update
  *
  * Calculate the best grid for the statistics based on the pipeline handler BDS
  * output, and parse the minimum and maximum exposure and analogue gain control
@@ -434,8 +360,7 @@ void IPAIPU3::calculateBdsGrid(const Size &bdsOutputSize)
  * All algorithm modules are called to allow them to prepare the
  * \a IPASessionConfiguration structure for the \a IPAContext.
  */
-int IPAIPU3::configure(const IPAConfigInfo &configInfo,
-		       ControlInfoMap *ipaControls)
+int IPAIPU3::configure(const IPAConfigInfo &configInfo)
 {
 	if (configInfo.sensorControls.empty()) {
 		LOG(IPAIPU3, Error) << "No sensor controls provided";
@@ -464,9 +389,6 @@ int IPAIPU3::configure(const IPAConfigInfo &configInfo,
 		return -EINVAL;
 	}
 
-	/* Update the camera controls using the new sensor settings. */
-	updateControls(sensorInfo_, sensorCtrls_, ipaControls);
-
 	/* Update the IPASessionConfiguration using the sensor settings. */
 	updateSessionConfiguration(sensorCtrls_);
 
diff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp
index a5a35b6585c6..8c5b6c36ae0b 100644
--- a/src/libcamera/pipeline/ipu3/ipu3.cpp
+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp
@@ -26,6 +26,7 @@
 #include "libcamera/internal/camera.h"
 #include "libcamera/internal/camera_lens.h"
 #include "libcamera/internal/camera_sensor.h"
+#include "libcamera/internal/control_ids.h"
 #include "libcamera/internal/device_enumerator.h"
 #include "libcamera/internal/framebuffer.h"
 #include "libcamera/internal/ipa_manager.h"
@@ -82,8 +83,6 @@ public:
 	/* Requests queued to the CIO2 device but not yet processed by the ImgU. */
 	std::queue<Request *> processingRequests_;
 
-	ControlInfoMap ipaControls_;
-
 private:
 	void metadataReady(unsigned int id, const ControlList &metadata);
 	void paramsBufferReady(unsigned int id);
@@ -670,7 +669,7 @@ int PipelineHandlerIPU3::configure(Camera *camera, CameraConfiguration *c)
 	configInfo.bdsOutputSize = config->imguConfig().bds;
 	configInfo.iif = config->imguConfig().iif;
 
-	ret = data->ipa_->configure(configInfo, &data->ipaControls_);
+	ret = data->ipa_->configure(configInfo);
 	if (ret) {
 		LOG(IPU3, Error) << "Failed to configure IPA: "
 				 << strerror(-ret);
@@ -946,9 +945,6 @@ bool PipelineHandlerIPU3::match(DeviceEnumerator *enumerator)
  * Initialize the camera controls by calculating controls which the pipeline
  * is reponsible for and merge them with the controls computed by the IPA.
  *
- * This function needs data->ipaControls_ to be initialized by the IPA init()
- * function at camera creation time. Always call this function after IPA init().
- *
  * \return 0 on success or a negative error code otherwise
  */
 int PipelineHandlerIPU3::initControls(IPU3CameraData *data)
@@ -978,9 +974,6 @@ int PipelineHandlerIPU3::initControls(IPU3CameraData *data)
  * Compute the camera controls by calculating controls which the pipeline
  * is reponsible for and merge them with the controls computed by the IPA.
  *
- * This function needs data->ipaControls_ to be refreshed when a new
- * configuration is applied to the camera by the IPA configure() function.
- *
  * Always call this function after IPA configure() to make sure to have a
  * properly refreshed IPA controls list.
  *
@@ -1059,9 +1052,21 @@ int PipelineHandlerIPU3::updateControls(IPU3CameraData *data)
 
 	controls[&controls::ScalerCrop] = ControlInfo(minCrop, maxCrop, maxCrop);
 
-	/* Add the IPA registered controls to list of camera controls. */
-	for (const auto &ipaControl : data->ipaControls_)
-		controls[ipaControl.first] = ipaControl.second;
+	/*
+	 * Translate the sensor controls to Camera controls.
+	 *
+	 * Exposure time and the frame duration limits are reported directly
+	 * from the sensor.
+	 */
+	const ControlInfoMap &sensorControls = sensor->controls();
+
+	if (sensorControls.count(&controls::internal::ExposureTime))
+		controls[&controls::ExposureTime] =
+			sensorControls.at(&controls::internal::ExposureTime);
+
+	if (sensorControls.count(&controls::internal::FrameDuration))
+		controls[&controls::FrameDurationLimits] =
+			sensorControls.at(&controls::internal::FrameDuration);
 
 	data->controlInfo_ = ControlInfoMap(std::move(controls),
 					    controls::controls);
@@ -1237,8 +1242,7 @@ int IPU3CameraData::loadIPA()
 	if (ret)
 		return ret;
 
-	ret = ipa_->init(IPASettings{ "", sensor->model() }, sensorInfo,
-			 sensor->v4l2Controls(), &ipaControls_);
+	ret = ipa_->init(IPASettings{ "", sensor->model() }, sensorInfo);
 	if (ret) {
 		LOG(IPU3, Error) << "Failed to initialise the IPU3 IPA";
 		return ret;
