diff --git a/prdoc/pr_2823.prdoc b/prdoc/pr_2823.prdoc
new file mode 100644
index 0000000000000000000000000000000000000000..64a309969efb353fe7d4d93b6a3e485e024f11f7
--- /dev/null
+++ b/prdoc/pr_2823.prdoc
@@ -0,0 +1,11 @@
+title: "`fungible::Unbalanced::decrease_balance`: Handle `precision` properly"
+
+doc:
+  - audience: Runtime Dev
+    description: |
+      `fungible::Unbalanced::decrease_balance` will now handle `precision` properly. This means when
+      passing `Exact`, it will ensure that the available balance is bigger or equal to the `amount`
+      that should be deducted.
+
+crates:
+  - name: "frame-support"
diff --git a/substrate/frame/balances/src/tests/fungible_tests.rs b/substrate/frame/balances/src/tests/fungible_tests.rs
index 8bf0509d8f77e00802e0378eaa4c9ec26e341534..52fbe10bedec0f7131fe35fa7e6f809968741d42 100644
--- a/substrate/frame/balances/src/tests/fungible_tests.rs
+++ b/substrate/frame/balances/src/tests/fungible_tests.rs
@@ -146,7 +146,7 @@ fn unbalanced_trait_decrease_balance_works_2() {
 		assert_eq!(Balances::total_balance_on_hold(&1337), 60);
 		assert_noop!(
 			Balances::decrease_balance(&1337, 40, Exact, Expendable, Polite),
-			Error::<Test>::InsufficientBalance
+			TokenError::FundsUnavailable
 		);
 		assert_eq!(Balances::decrease_balance(&1337, 39, Exact, Expendable, Polite), Ok(39));
 		assert_eq!(<Balances as fungible::Inspect<_>>::balance(&1337), 1);
@@ -468,3 +468,28 @@ fn emit_events_with_changing_freezes() {
 		assert_eq!(events(), [RuntimeEvent::Balances(crate::Event::Thawed { who: 1, amount: 15 })]);
 	});
 }
+
+#[test]
+fn withdraw_precision_exact_works() {
+	ExtBuilder::default()
+		.existential_deposit(1)
+		.monied(true)
+		.build_and_execute_with(|| {
+			assert_ok!(Balances::set_freeze(&TestId::Foo, &1, 10));
+			assert_eq!(Balances::account(&1).free, 10);
+			assert_eq!(Balances::account(&1).frozen, 10);
+
+			// `BestEffort` will not reduce anything
+			assert_ok!(<Balances as fungible::Balanced<_>>::withdraw(
+				&1, 5, BestEffort, Preserve, Polite
+			));
+
+			assert_eq!(Balances::account(&1).free, 10);
+			assert_eq!(Balances::account(&1).frozen, 10);
+
+			assert_noop!(
+				<Balances as fungible::Balanced<_>>::withdraw(&1, 5, Exact, Preserve, Polite),
+				TokenError::FundsUnavailable
+			);
+		});
+}
diff --git a/substrate/frame/support/src/traits/tokens/fungible/regular.rs b/substrate/frame/support/src/traits/tokens/fungible/regular.rs
index aece73777d280ee40e70a2270bae7abe9189f774..87c6ef68d77d6c8ca0b88d650126c7e472126b85 100644
--- a/substrate/frame/support/src/traits/tokens/fungible/regular.rs
+++ b/substrate/frame/support/src/traits/tokens/fungible/regular.rs
@@ -181,9 +181,16 @@ pub trait Unbalanced<AccountId>: Inspect<AccountId> {
 	) -> Result<Self::Balance, DispatchError> {
 		let old_balance = Self::balance(who);
 		let free = Self::reducible_balance(who, preservation, force);
-		if let BestEffort = precision {
-			amount = amount.min(free);
+		match precision {
+			BestEffort => {
+				amount = amount.min(free);
+			},
+			Exact =>
+				if free < amount {
+					return Err(TokenError::FundsUnavailable.into())
+				},
 		}
+
 		let new_balance = old_balance.checked_sub(&amount).ok_or(TokenError::FundsUnavailable)?;
 		if let Some(dust) = Self::write_balance(who, new_balance)? {
 			Self::handle_dust(Dust(dust));