diff --git a/src/ipa/rkisp1/algorithms/agc.cpp b/src/ipa/rkisp1/algorithms/agc.cpp
index 55cadb1793a5..1496a118ae2b 100644
--- a/src/ipa/rkisp1/algorithms/agc.cpp
+++ b/src/ipa/rkisp1/algorithms/agc.cpp
@@ -156,6 +156,15 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData)
 				ControlValue(controls::AnalogueGainModeManual) } },
 			    ControlValue(controls::AnalogueGainModeAuto));
 	context.ctrlMap[&controls::ExposureValue] = ControlInfo(-8.0f, 8.0f, 0.0f);
+	/*
+	 * Insert the controlInfo for sync. Since FrameDurationLimits is only
+	 * set *after* the algorithms are initialized, we have no information
+	 * on it here. Use a sensible default here and update it later in
+	 * configure().
+	 * \todo Move FrameDurationLimits from the base IPA to AGC
+	 */
+	context.ctrlMap[&controls::SyncAdjustment] = SyncHelper::controlInfo(120'000);
+	/* Insert the controls for agc */
 	context.ctrlMap.merge(controls());
 
 	return 0;
@@ -208,7 +217,11 @@ int Agc::configure(IPAContext &context, const IPACameraSensorInfo &configInfo)
 
 	context.activeState.agc.automatic.yTarget = effectiveYTarget();
 
+	context.ctrlMap[&controls::SyncAdjustment] =
+		SyncHelper::controlInfo(frameDurationLimits.max().get<int64_t>());
+
 	resetFrameCount();
+	sync_.resetSync();
 
 	return 0;
 }
@@ -334,6 +347,10 @@ void Agc::queueRequest(IPAContext &context,
 	}
 	frameContext.agc.minFrameDuration = agc.minFrameDuration;
 	frameContext.agc.maxFrameDuration = agc.maxFrameDuration;
+
+	const auto &sync = controls.get(controls::SyncAdjustment);
+	if (sync)
+		sync_.setSync(*sync, frameContext.agc.minFrameDuration);
 }
 
 /**
@@ -453,6 +470,7 @@ void Agc::fillMetadata(IPAContext &context, IPAFrameContext &frameContext,
 	metadata.set(controls::AeExposureMode, frameContext.agc.exposureMode);
 	metadata.set(controls::AeConstraintMode, frameContext.agc.constraintMode);
 	metadata.set(controls::ExposureValue, frameContext.agc.exposureValue);
+	metadata.set(controls::SyncAdjustment, frameContext.agc.syncAdjustment.count());
 }
 
 /**
@@ -511,7 +529,9 @@ void Agc::processFrameDuration(IPAContext &context,
 	IPACameraSensorInfo &sensorInfo = context.sensorInfo;
 	utils::Duration lineDuration = context.configuration.sensor.lineDuration;
 
-	frameContext.agc.vblank = (frameDuration / lineDuration) - sensorInfo.outputSize.height;
+	utils::Duration sync = sync_.getSync();
+	frameContext.agc.vblank = ((frameDuration + sync) / lineDuration) - sensorInfo.outputSize.height;
+	frameContext.agc.syncAdjustment = sync;
 
 	/* Update frame duration accounting for line length quantization. */
 	frameContext.agc.frameDuration = (sensorInfo.outputSize.height + frameContext.agc.vblank) * lineDuration;
diff --git a/src/ipa/rkisp1/algorithms/agc.h b/src/ipa/rkisp1/algorithms/agc.h
index 7867eed9c4e3..c6cc20679cf7 100644
--- a/src/ipa/rkisp1/algorithms/agc.h
+++ b/src/ipa/rkisp1/algorithms/agc.h
@@ -15,6 +15,7 @@
 #include <libcamera/geometry.h>
 
 #include "libipa/agc_mean_luminance.h"
+#include "libipa/sync_helper.h"
 
 #include "algorithm.h"
 
@@ -58,6 +59,8 @@ private:
 	Span<const uint8_t> weights_;
 
 	std::map<int32_t, std::vector<uint8_t>> meteringModes_;
+
+	SyncHelper sync_;
 };
 
 } /* namespace ipa::rkisp1::algorithms */
diff --git a/src/ipa/rkisp1/ipa_context.h b/src/ipa/rkisp1/ipa_context.h
index fa748811be74..3a5b499e088e 100644
--- a/src/ipa/rkisp1/ipa_context.h
+++ b/src/ipa/rkisp1/ipa_context.h
@@ -164,6 +164,7 @@ struct IPAFrameContext : public FrameContext {
 		bool updateMetering;
 		bool autoExposureModeChange;
 		bool autoGainModeChange;
+		utils::Duration syncAdjustment;
 	} agc;
 
 	struct {
