The Norwegian forward tapped home a pinpoint Kevin De Bruyne cross early in the second half to score City’s first-ever league goal at the Tottenham Hotspur Stadium and netted a late penalty to seal the three points.
It takes Pep Guardiola’s team two points clear of Arsenal at the top of the table and means victory at the Etihad against West Ham on Sunday will make them champions for a fourth straight season, regardless of the Gunners’ result against Everton.
No team in English top-flight history has ever won four titles in a row.
Defeat for Spurs also guarantees that Aston Villa will finish in the fourth Champions League spot, joining City, Arsenal and Liverpool in Europe’s top-tier competition next season
The build-up to the game in north London was dominated by a fierce debate over whether home fans wanted their own team to lose in order to leave City in the driving seat, with Arsenal their nearest challengers.
The Spurs supporters made their feelings towards their bitter local rivals clear in the opening minutes, with chants of “Stand up if you hate Arsenal” ringing around the stadium.
Both sides settled quickly and Spurs had the first sight of goal when a raking ball from Pierre-Emile Hojbjerg found Brennan Johnson on the right.
Johnson squared for Rodrigo Bentancur, who unleashed a fierce shot that Ederson tipped over.
Spurs goalkeeper Guglielmo Vicario kept out Phil Foden’s close-range shot after 15 minutes with a strong right hand.
City, who came into the match on an unbeaten run of 21 matches, were short of their fluent best while Spurs struggled to put the finishing touches to their attacking moves.
The game opened up towards the end of the first period, with City defender Josko Gvardiol flashing a shot over the bar from a tight angle but the sides finished the opening 45 minutes with just one shot on target apiece.
City break deadlock
Moments after the re-start Vicario was forced to dive full length to keep out a stinging De Bruyne effort while Son Heung-min went close at the other end after being found by Johnson.
But City broke the deadlock in the 51st minute when Bernardo Silva found De Bruyne in the box and the Belgian crossed for Haaland to slot home from point-blank range.
Thousands of Spurs fans chanted “Are you watching Arsenal” as the City fans celebrated in their corner.
The game then became disjointed as first De Bruyne was hurt by a Pape Sarr tackle on his ankle before Ederson took a blow to the head in denying Cristian Romero and was replaced minutes later by Stefan Ortega.
The German was called into action immediately, keeping out substitute Dejan Kulusevski’s close-range shot with his legs.
The visitors’ hearts were in their mouths when Son burst through with five minutes of normal time remaining but Ortega saved with his legs when he seemed likely to score.
Guardiola fell to the ground, clutching his head in disbelief.
Instead City were awarded a penalty when Pedro Porro brought down substitute Jeremy Doku and Haaland smashed home in the 91st minute to spark wild celebrations from the players in front of the City faithful, taking his league tally to 27 goals for the season.
Last year’s treble winners will prepare for Sunday’s finale knowing they stand just 90 minutes away from creating another slice of football history.