The visitors took the lead at Signal Iduna Park through a spot-kick from Ishak Belfodil in the 18th minute.
Haaland – set to head to the Premier League next season after Manchester City triggered his £51.1million release clause – had Dortmund level from a penalty with 20 minutes left.
Jude Bellingham then played in Youssoufa Moukoko to slot home from a tight angle in the 84th minute – which coupled with a late winner for Stuttgart sent Felix Magath’s side into the relegation play-offs.
Stuttgart had started the day in 16th place and looked set to stay there after Anthony Modeste had headed in equaliser for Cologne on the hour to cancel out Sasa Kalajdzic’s early opener.
However, in stoppage time, Wataru Endo nodded in a from a corner to spark pandemonium around the Mercedes-Benz Arena.
RB Leipzig secured fourth spot and with it a place in the Champions League after a late goal from defender Willi Orban salvaged a 1-1 draw at relegated Arminia Bielefeld.
Janni Serra had bundled the home side in front with 20 minutes left, which had looked enough to sign off from the top flight with a win – only for Orban to nod home a stoppage-time equaliser from a free-kick.
Robert Lewandowski, who has been linked with a summer move away, took his Bundesliga goal tally to 35 as champions Bayern Munich ended the campaign with a 2-2 draw at Wolfsburg – where they had been 2-0 up at half-time.
Union Berlin beat Bochum 3-2, with Taiwo Awoniyi scoring twice, to finish in fifth place, a point behind Leipzig, and go into the Europa League.
A last-minute goal from Exequiel Palacios saw third-placed Bayer Leverkusen end the campaign with a 2-1 home win over Freiburg, who finish sixth.
Marcus Ingvartsen scored twice as Mainz held Europa League finalists Eintracht Frankfurt to a 2-2 draw, while bottom club Greuther Furth went down 2-1 at Augsburg, where Michael Gregoritsch struck a late winner.
Jonas Hofmann grabbed a brace to help Borussia Monchengladbach come from behind to sweep aside Hoffenheim 5-1.
In Serie A, Europa League finalists Roma saw bottom club Venezia, whose relegation was confirmed earlier on Saturday, battle to a 1-1 draw with 10 men at Stadio Olimpico.
David Okereke headed the visitors into a shock first-minute lead, before defender Sofian Kiyine was shown a straight red card for kicking out at Lorenzo Pellegrini.
After hitting the woodwork twice in the second half Roma eventually were level through Eldor Shomurodov with 15 minutes left.
Spezia secured their Serie A status after coming from behind to win 3-2 at Udinese, moving seven points clear of the drop zone.
Empoli had earlier drawn 1-1 with survival-battlers Salernitana, a result which confirmed Venizia’s relegation.
A first-half goal from Josip Brekalo proved enough to give Torino a 1-0 win at Hellas Verona.
Saturday’s only LaLiga match saw Espanyol and Valencia play out a 1-1 draw at the RCDE Stadium, which extended the hosts winless run to six games.
In Ligue 1, Monaco moved into second place to boost their hopes of direct qualification for the Champions League as a hat-trick from Wissam Ben Yedder helped them fight back to beat Brest 4-2 at the Stade Louis II.
Marseille are now down to third on goal difference after slipping to a 2-0 defeat at Rennes, who are just three points behind in fourth.
Champions Paris St Germain coasted to a 4-0 win at Montpellier, with Lionel Messi on target twice in the opening 20 minutes.
Strasbourg sit fifth after a 1-0 win over Clermont, while Nice saw their own European ambitions dented by a 3-1 home defeat against Lille, with Canada forward Jonathan David scoring twice.
Lens are still in the European hunt after a 3-1 win at Troyes, while Lyon beat Nantes 3-2 and it was goalless between Bordeaux, who finished with 10 men, and Lorient.
At the other end of the table, Metz kept their faint hopes of Ligue 1 survival alive with a 1-0 win over Angers which leaves them 18th and in the relegation play-off spot.
St Etienne, though, slipped into the drop zone after losing 2-1 at home to Reims.