diff --git a/src/ipa/ipu3/ipu3_awb.cpp b/src/ipa/ipu3/algorithms/awb.cpp
similarity index 92%
rename from src/ipa/ipu3/ipu3_awb.cpp
rename to src/ipa/ipu3/algorithms/awb.cpp
index 043c3838..92a41b65 100644
--- a/src/ipa/ipu3/ipu3_awb.cpp
+++ b/src/ipa/ipu3/algorithms/awb.cpp
@@ -2,9 +2,9 @@
 /*
  * Copyright (C) 2021, Ideas On Board
  *
- * ipu3_awb.cpp - AWB control algorithm
+ * awb.cpp - AWB control algorithm
  */
-#include "ipu3_awb.h"
+#include "awb.h"
 
 #include <cmath>
 #include <numeric>
@@ -14,7 +14,7 @@
 
 namespace libcamera {
 
-namespace ipa::ipu3 {
+namespace ipa::ipu3::algorithms {
 
 LOG_DEFINE_CATEGORY(IPU3Awb)
 
@@ -134,7 +134,7 @@ static const struct ipu3_uapi_ccm_mat_config imguCssCcmDefault = {
 	0, 0, 8191, 0
 };
 
-IPU3Awb::IPU3Awb()
+Awb::Awb()
 	: Algorithm()
 {
 	asyncResults_.blueGain = 1.0;
@@ -143,17 +143,19 @@ IPU3Awb::IPU3Awb()
 	asyncResults_.temperatureK = 4500;
 }
 
-IPU3Awb::~IPU3Awb()
+Awb::~Awb()
 {
 }
 
-void IPU3Awb::initialise(ipu3_uapi_params &params, const Size &bdsOutputSize, struct ipu3_uapi_grid_config &bdsGrid)
+int Awb::configure(IPAContext &context)
 {
+	ipu3_uapi_params &params = context.params;
+	Size &bdsOutputSize = context.awb.grid.bdsOutputSize;
+
 	params.use.acc_awb = 1;
 	params.acc_param.awb.config = imguCssAwbDefaults;
 
-	awbGrid_ = bdsGrid;
-	params.acc_param.awb.config.grid = awbGrid_;
+	awbGrid_ = context.awb.grid.bdsGrid;
 
 	params.use.acc_bnr = 1;
 	params.acc_param.bnr = imguCssBnrDefaults;
@@ -174,6 +176,8 @@ void IPU3Awb::initialise(ipu3_uapi_params &params, const Size &bdsOutputSize, st
 	params.acc_param.ccm = imguCssCcmDefault;
 
 	zones_.reserve(kAwbStatsSizeX * kAwbStatsSizeY);
+
+	return 0;
 }
 
 /**
@@ -190,7 +194,7 @@ void IPU3Awb::initialise(ipu3_uapi_params &params, const Size &bdsOutputSize, st
  * More detailed information can be found in:
  * https://en.wikipedia.org/wiki/Color_temperature#Approximation
  */
-uint32_t IPU3Awb::estimateCCT(double red, double green, double blue)
+uint32_t Awb::estimateCCT(double red, double green, double blue)
 {
 	/* Convert the RGB values to CIE tristimulus values (XYZ) */
 	double X = (-0.14282) * (red) + (1.54924) * (green) + (-0.95641) * (blue);
@@ -207,7 +211,7 @@ uint32_t IPU3Awb::estimateCCT(double red, double green, double blue)
 }
 
 /* Generate an RGB vector with the average values for each region */
-void IPU3Awb::generateZones(std::vector<RGB> &zones)
+void Awb::generateZones(std::vector<RGB> &zones)
 {
 	for (unsigned int i = 0; i < kAwbStatsSizeX * kAwbStatsSizeY; i++) {
 		RGB zone;
@@ -224,7 +228,7 @@ void IPU3Awb::generateZones(std::vector<RGB> &zones)
 }
 
 /* Translate the IPU3 statistics into the default statistics region array */
-void IPU3Awb::generateAwbStats(const ipu3_uapi_stats_3a *stats)
+void Awb::generateAwbStats(const ipu3_uapi_stats_3a *stats)
 {
 	uint32_t regionWidth = round(awbGrid_.width / static_cast<double>(kAwbStatsSizeX));
 	uint32_t regionHeight = round(awbGrid_.height / static_cast<double>(kAwbStatsSizeY));
@@ -256,7 +260,7 @@ void IPU3Awb::generateAwbStats(const ipu3_uapi_stats_3a *stats)
 	}
 }
 
-void IPU3Awb::clearAwbStats()
+void Awb::clearAwbStats()
 {
 	for (unsigned int i = 0; i < kAwbStatsSizeX * kAwbStatsSizeY; i++) {
 		awbStats_[i].bSum = 0;
@@ -267,7 +271,7 @@ void IPU3Awb::clearAwbStats()
 	}
 }
 
-void IPU3Awb::awbGreyWorld()
+void Awb::awbGreyWorld()
 {
 	LOG(IPU3Awb, Debug) << "Grey world AWB";
 	/*
@@ -307,7 +311,7 @@ void IPU3Awb::awbGreyWorld()
 	asyncResults_.blueGain = blueGain;
 }
 
-void IPU3Awb::calculateWBGains(const ipu3_uapi_stats_3a *stats)
+void Awb::calculateWBGains(const ipu3_uapi_stats_3a *stats)
 {
 	ASSERT(stats->stats_3a_status.awb_en);
 	zones_.clear();
@@ -322,7 +326,7 @@ void IPU3Awb::calculateWBGains(const ipu3_uapi_stats_3a *stats)
 	}
 }
 
-void IPU3Awb::updateWbParameters(ipu3_uapi_params &params)
+void Awb::updateWbParameters(ipu3_uapi_params &params)
 {
 	/*
 	 * Green gains should not be touched and considered 1.
@@ -340,6 +344,12 @@ void IPU3Awb::updateWbParameters(ipu3_uapi_params &params)
 	params.acc_param.ccm = imguCssCcmDefault;
 }
 
-} /* namespace ipa::ipu3 */
+void Awb::process(IPAContext &context)
+{
+	calculateWBGains(context.stats);
+	updateWbParameters(context.params);
+}
+
+} /* namespace ipa::ipu3::algorithms */
 
 } /* namespace libcamera */
diff --git a/src/ipa/ipu3/ipu3_awb.h b/src/ipa/ipu3/algorithms/awb.h
similarity index 79%
rename from src/ipa/ipu3/ipu3_awb.h
rename to src/ipa/ipu3/algorithms/awb.h
index 8b05ac03..37690b37 100644
--- a/src/ipa/ipu3/ipu3_awb.h
+++ b/src/ipa/ipu3/algorithms/awb.h
@@ -2,10 +2,10 @@
 /*
  * Copyright (C) 2021, Ideas On Board
  *
- * ipu3_awb.h - IPU3 AWB control algorithm
+ * awb.h - IPU3 AWB control algorithm
  */
-#ifndef __LIBCAMERA_IPU3_AWB_H__
-#define __LIBCAMERA_IPU3_AWB_H__
+#ifndef __LIBCAMERA_IPU3_ALGORITHMS_AWB_H__
+#define __LIBCAMERA_IPU3_ALGORITHMS_AWB_H__
 
 #include <vector>
 
@@ -13,26 +13,24 @@
 
 #include <libcamera/geometry.h>
 
-#include "algorithms/algorithm.h"
-#include "libipa/algorithm.h"
+#include "algorithm.h"
 
 namespace libcamera {
 
-namespace ipa::ipu3 {
+namespace ipa::ipu3::algorithms {
 
 /* Region size for the statistics generation algorithm */
 static constexpr uint32_t kAwbStatsSizeX = 16;
 static constexpr uint32_t kAwbStatsSizeY = 12;
 
-class IPU3Awb : public ipa::Algorithm
+class Awb : public Algorithm
 {
 public:
-	IPU3Awb();
-	~IPU3Awb();
+	Awb();
+	~Awb();
 
-	void initialise(ipu3_uapi_params &params, const Size &bdsOutputSize, struct ipu3_uapi_grid_config &bdsGrid);
-	void calculateWBGains(const ipu3_uapi_stats_3a *stats);
-	void updateWbParameters(ipu3_uapi_params &params);
+	int configure(IPAContext &context) override;
+	void process(IPAContext &context) override;
 
 	struct Ipu3AwbCell {
 		unsigned char greenRedAvg;
@@ -73,6 +71,9 @@ public:
 	};
 
 private:
+	void calculateWBGains(const ipu3_uapi_stats_3a *stats);
+	void updateWbParameters(ipu3_uapi_params &params);
+
 	void generateZones(std::vector<RGB> &zones);
 	void generateAwbStats(const ipu3_uapi_stats_3a *stats);
 	void clearAwbStats();
@@ -86,7 +87,7 @@ private:
 	AwbStatus asyncResults_;
 };
 
-} /* namespace ipa::ipu3 */
+} /* namespace ipa::ipu3::algorithms */
 
 } /* namespace libcamera*/
-#endif /* __LIBCAMERA_IPU3_AWB_H__ */
+#endif /* __LIBCAMERA_IPU3_ALGORITHMS_AWB_H__ */
diff --git a/src/ipa/ipu3/algorithms/meson.build b/src/ipa/ipu3/algorithms/meson.build
index f71d1e61..df36d719 100644
--- a/src/ipa/ipu3/algorithms/meson.build
+++ b/src/ipa/ipu3/algorithms/meson.build
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: CC0-1.0
 
 ipu3_ipa_algorithms = files([
+    'awb.cpp',
     'contrast.cpp',
 ])
diff --git a/src/ipa/ipu3/ipa_context.h b/src/ipa/ipu3/ipa_context.h
index 5d717be5..c43b275b 100644
--- a/src/ipa/ipu3/ipa_context.h
+++ b/src/ipa/ipu3/ipa_context.h
@@ -11,6 +11,8 @@
 
 #include <linux/intel-ipu3.h>
 
+#include <libcamera/geometry.h>
+
 namespace libcamera {
 
 namespace ipa::ipu3 {
@@ -21,6 +23,16 @@ struct IPAContext {
 
 	/* Output Parameters which will be written to the hardware */
 	ipu3_uapi_params params;
+
+	/* AWB specific parameters to share */
+	struct Awb {
+		struct Grid {
+			/* BDS grid plane config used by the kernel */
+			ipu3_uapi_grid_config bdsGrid;
+			/* BDS output size configured by the pipeline handler */
+			Size bdsOutputSize;
+		} grid;
+	} awb;
 };
 
 } /* namespace ipa::ipu3 */
diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
index 7035802f..82506461 100644
--- a/src/ipa/ipu3/ipu3.cpp
+++ b/src/ipa/ipu3/ipu3.cpp
@@ -23,11 +23,11 @@
 #include "libcamera/internal/framebuffer.h"
 
 #include "algorithms/algorithm.h"
+#include "algorithms/awb.h"
 #include "algorithms/contrast.h"
 #include "ipa_context.h"
 
 #include "ipu3_agc.h"
-#include "ipu3_awb.h"
 #include "libipa/camera_sensor_helper.h"
 
 static constexpr uint32_t kMaxCellWidthPerSet = 160;
@@ -81,8 +81,6 @@ private:
 	uint32_t minGain_;
 	uint32_t maxGain_;
 
-	/* Interface to the AWB algorithm */
-	std::unique_ptr<IPU3Awb> awbAlgo_;
 	/* Interface to the AEC/AGC algorithm */
 	std::unique_ptr<IPU3Agc> agcAlgo_;
 	/* Interface to the Camera Helper */
@@ -105,6 +103,7 @@ int IPAIPU3::init(const IPASettings &settings)
 	}
 
 	/* Construct our Algorithms */
+	algorithms_.emplace_back(new algorithms::Awb());
 	algorithms_.emplace_back(new algorithms::Contrast());
 
 	/* Reset all the hardware settings */
@@ -138,7 +137,7 @@ void IPAIPU3::calculateBdsGrid(const Size &bdsOutputSize)
 	uint32_t minError = std::numeric_limits<uint32_t>::max();
 	Size best;
 	Size bestLog2;
-	bdsGrid_ = {};
+	ipu3_uapi_grid_config &bdsGrid = context_.awb.grid.bdsGrid;
 
 	for (uint32_t widthShift = 3; widthShift <= 7; ++widthShift) {
 		uint32_t width = std::min(kMaxCellWidthPerSet,
@@ -162,14 +161,14 @@ void IPAIPU3::calculateBdsGrid(const Size &bdsOutputSize)
 		}
 	}
 
-	bdsGrid_.width = best.width >> bestLog2.width;
-	bdsGrid_.block_width_log2 = bestLog2.width;
-	bdsGrid_.height = best.height >> bestLog2.height;
-	bdsGrid_.block_height_log2 = bestLog2.height;
+	bdsGrid.width = best.width >> bestLog2.width;
+	bdsGrid.block_width_log2 = bestLog2.width;
+	bdsGrid.height = best.height >> bestLog2.height;
+	bdsGrid.block_height_log2 = bestLog2.height;
 
 	LOG(IPAIPU3, Debug) << "Best grid found is: ("
-			    << (int)bdsGrid_.width << " << " << (int)bdsGrid_.block_width_log2 << ") x ("
-			    << (int)bdsGrid_.height << " << " << (int)bdsGrid_.block_height_log2 << ")";
+			    << (int)bdsGrid.width << " << " << (int)bdsGrid.block_width_log2 << ") x ("
+			    << (int)bdsGrid.height << " << " << (int)bdsGrid.block_height_log2 << ")";
 }
 
 int IPAIPU3::configure(const IPAConfigInfo &configInfo)
@@ -211,13 +210,13 @@ int IPAIPU3::configure(const IPAConfigInfo &configInfo)
 
 	defVBlank_ = itVBlank->second.def().get<int32_t>();
 
+	/* Prepare AWB parameters */
 	calculateBdsGrid(configInfo.bdsOutputSize);
+	context_.awb.grid.bdsOutputSize = configInfo.bdsOutputSize;
 
 	configureAlgorithms();
 
-	awbAlgo_ = std::make_unique<IPU3Awb>();
-	awbAlgo_->initialise(context_.params, configInfo.bdsOutputSize, bdsGrid_);
-
+	bdsGrid_ = context_.awb.grid.bdsGrid;
 	agcAlgo_ = std::make_unique<IPU3Agc>();
 	agcAlgo_->initialise(bdsGrid_, sensorInfo_);
 
@@ -293,9 +292,6 @@ void IPAIPU3::processControls([[maybe_unused]] unsigned int frame,
 
 void IPAIPU3::fillParams(unsigned int frame, ipu3_uapi_params *params)
 {
-	if (agcAlgo_->updateControls())
-		awbAlgo_->updateWbParameters(context_.params);
-
 	*params = context_.params;
 
 	IPU3Action op;
@@ -349,8 +345,6 @@ void IPAIPU3::parseStatistics(unsigned int frame,
 	agcAlgo_->process(stats, exposure_, gain);
 	gain_ = camHelper_->gainCode(gain);
 
-	awbAlgo_->calculateWBGains(stats);
-
 	if (agcAlgo_->updateControls())
 		setControls(frame);
 
diff --git a/src/ipa/ipu3/meson.build b/src/ipa/ipu3/meson.build
index fcb27d68..d1126947 100644
--- a/src/ipa/ipu3/meson.build
+++ b/src/ipa/ipu3/meson.build
@@ -7,7 +7,6 @@ ipa_name = 'ipa_ipu3'
 ipu3_ipa_sources = files([
     'ipu3.cpp',
     'ipu3_agc.cpp',
-    'ipu3_awb.cpp',
 ])
 
 ipu3_ipa_sources += ipu3_ipa_algorithms
