Houston led 4-0 after 3 1/2 innings and 5-3 after 4 1/2 but still lost their seventh straight game. The Astros have a major-league worst 39-86 record.
St. Louis took control of the game with a five-run fifth inning in which Holliday doubled in three runs. The Cardinals added a single run in the sixth and four runs in the eighth. That rally was capped by an RBI single by Freese.
Jake Westbrook (13-9) got the win despite being charged with seven hits and five runs -- all earned -- in just five innings.
Houston starter Dallas Keuchel (1-6) was chased in the fifth in taking the loss. He was touched for five hits and one walk. Five of the six runs he allowed were earned.
Keuchel had a sacrifice fly and Jose Altuve drove in a pair of runs as the Astros built a 4-0 lead. St. Louis answered in the bottom of the fourth with a three-run home run by Freese.
Scott Moore had a sacrifice fly for a 5-3 lead for Houston in the fifth before the Cardinals batted around in the bottom of the inning fifth with Holliday contributing a bases-loaded double.